├── .gitignore ├── .travis.yml ├── Cargo.toml ├── Changelog.md ├── LICENSE ├── README.md ├── appveyor.yml ├── clippy.toml ├── examples ├── dig.rs ├── lookup.rs └── rusthome.rs └── src ├── bits ├── charstr.rs ├── compose.rs ├── header.rs ├── message.rs ├── message_builder.rs ├── mod.rs ├── name │ ├── builder.rs │ ├── dname.rs │ ├── from_str.rs │ ├── iter.rs │ ├── label.rs │ ├── mod.rs │ ├── parsed.rs │ └── plain.rs ├── opt │ ├── mod.rs │ ├── rfc5001.rs │ ├── rfc6975.rs │ ├── rfc7314.rs │ ├── rfc7828.rs │ ├── rfc7830.rs │ ├── rfc7871.rs │ ├── rfc7873.rs │ ├── rfc7901.rs │ └── rfc8145.rs ├── parse.rs ├── question.rs ├── rdata.rs └── record.rs ├── iana ├── class.rs ├── macros.rs ├── mod.rs ├── opcode.rs ├── opt.rs ├── rcode.rs ├── rtype.rs └── secalg.rs ├── lib.rs ├── master ├── bufscanner.rs ├── entry.rs ├── error.rs ├── mod.rs ├── reader.rs ├── record.rs └── scanner.rs ├── rdata ├── generic.rs ├── macros.rs ├── mod.rs ├── rfc1035.rs ├── rfc2782.rs └── rfc3596.rs ├── resolv ├── channel.rs ├── conf.rs ├── error.rs ├── intro.rs ├── lookup │ ├── addr.rs │ ├── host.rs │ ├── mod.rs │ ├── records.rs │ ├── search.rs │ └── srv.rs ├── mod.rs ├── public.rs ├── request.rs ├── tcp.rs ├── transport │ ├── mod.rs │ ├── multiplex.rs │ ├── pending.rs │ ├── sequential.rs │ ├── single.rs │ └── spawn.rs └── udp.rs └── utils ├── mod.rs └── netdb.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.o 3 | *.so 4 | *.rlib 5 | *.dll 6 | 7 | # Executables 8 | *.exe 9 | 10 | # Generated by Cargo 11 | /target/ 12 | 13 | # Library, so no Cargo.lock 14 | Cargo.lock 15 | 16 | # Editor cruft 17 | *.*.swp 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "domain" 3 | version = "0.2.5" 4 | authors = ["Martin Hoffmann "] 5 | description = "A DNS library for Rust." 6 | documentation = "https://docs.rs/domain/" 7 | homepage = "https://github.com/partim/domain" 8 | repository = "https://github.com/partim/domain" 9 | readme = "README.md" 10 | keywords = ["DNS", "domain", "resolver", "futures"] 11 | license = "MIT" 12 | 13 | [lib] 14 | name = "domain" 15 | path = "src/lib.rs" 16 | 17 | [dependencies] 18 | byteorder = "1.2" 19 | rand = "0.4" 20 | futures = "0.1.18" 21 | tokio-core = "0.1.12" 22 | 23 | [dev-dependencies] 24 | argparse = "0.2" 25 | native-tls = "0.1.5" 26 | tokio-io = "0.1.5" 27 | tokio-tls = "0.1.4" 28 | 29 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | ## 0.2.5 2 | 3 | Breaking Changes 4 | 5 | New 6 | 7 | Bug fixes 8 | 9 | Dependencies 10 | 11 | 12 | ## 0.2.4 13 | 14 | Bug fixes 15 | 16 | * fixes parsing of TXT records. 17 | 18 | 19 | ## 0.2.3 20 | 21 | Dependencies 22 | 23 | * updated byteorder to 1.2 24 | * updated rand to 0.4 25 | * updated futures and tokio to latest 0.1. 26 | 27 | 28 | ## 0.2.2 29 | 30 | New 31 | 32 | * `bits` module 33 | 34 | * `bits::opt`` module for parsing and composing of OPT records and OPT 35 | options. 36 | 37 | Bug fixes 38 | 39 | * `resolver` module 40 | 41 | * Resolver may crash with ‘rotate’ option and failing upstream servers. 42 | ([#20](https://github.com/partim/domain/issues/20)). 43 | 44 | Dependencies 45 | 46 | * updated tokio-core to 0.1.9. 47 | 48 | 49 | ## 0.2.1 50 | 51 | Breaking Changes 52 | 53 | * `bits` module 54 | 55 | * `DNameBuf::from_iter` renamed to `DNameBuf::try_from_iter` to avoid 56 | confusing with `FromIterator` trait. 57 | 58 | New 59 | 60 | * `rdata` module 61 | 62 | * Support for SRV records. (Thanks, @ThibG!) 63 | 64 | * `resolver` module 65 | 66 | * Resolving server addresses with SRV records. (Thanks, @ThibG!) 67 | 68 | Bug fixes 69 | 70 | * `bits` module 71 | 72 | * Correctly build later sections of a message in `MessageBuilder`. 73 | 74 | Dependencies 75 | 76 | * updated to futures 0.1.14 and tokio-core 0.1.8. 77 | 78 | 79 | ## 0.2.0 80 | 81 | Breaking Changes 82 | 83 | * `bits` module 84 | 85 | * Domain name iterators have been reworked: 86 | 87 | * `NameLabels` and `NameLabelettes` are now `DoubleEndedIterator`s. 88 | 89 | * `RevNameLabels` and `RevNameLabelettes` are gone. Use the 90 | `next_back()` methods on the regular iterators instead. 91 | 92 | * `DName` has lost the `rev_labels()` and `rev_labelettes()` methods. 93 | 94 | * Method name harmonization: 95 | 96 | * `DNameSlice::iter()` is now `DNameSlice::labels()`, 97 | * `ParsedDName::iter()` is now `ParsedDName::labels()`. 98 | 99 | * `resolv` module 100 | 101 | * Almost complete rewrite of the actual resolver to be compatible with 102 | tokio’s 0.1 release. 103 | 104 | * `ResolverTask` is gone. You can now run queries directly on a 105 | resolver. 106 | 107 | * The lookup functions now return a concrete type as their future 108 | instead of a boxed future. The names of their success types have been 109 | changed in order to harmonize names of future returning functions and 110 | the name of their returned types (as in `lookup_host()` returns a 111 | `LookupHost` as its future). The functionality of the success types 112 | has not changed. 113 | 114 | 115 | Bug fixes 116 | 117 | 118 | New 119 | 120 | 121 | ## 0.1.0 122 | 123 | Initial public release. 124 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 cloudshipping 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # domain 2 | 3 | The _domain_ crate has been adopted by [NLnet Labs], 4 | makers of fine DNS software such as [Unbound] and [NSD]. 5 | It is therefore now available at [NLnetLabs/domain]. 6 | 7 | [NLnet Labs]: https://nlnetlabs.nl/ 8 | [Unbound]: https://nlnetlabs.nl/projects/unbound/about/ 9 | [NSD]: https://nlnetlabs.nl/projects/nsd/about/ 10 | [NLnetLabs/domain]: https://github.com/NLnetLabs/domain 11 | 12 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - TARGET: x86_64-pc-windows-msvc 4 | install: 5 | - set PATH=C:\Program Files\Git\mingw64\bin;%PATH% 6 | - curl -sSf -o rustup-init.exe https://win.rustup.rs/ 7 | - rustup-init.exe -y --default-host %TARGET% 8 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 9 | - rustc -V 10 | - cargo -V 11 | 12 | build: false 13 | 14 | test_script: 15 | - cargo build 16 | - cargo test 17 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | doc-valid-idents = ["CLASSes", "IPv4", "IPv6", "OpCodes", "RRset", "RRsets"] 2 | 3 | -------------------------------------------------------------------------------- /examples/dig.rs: -------------------------------------------------------------------------------- 1 | extern crate argparse; 2 | extern crate domain; 3 | extern crate tokio_core; 4 | 5 | use std::error; 6 | use std::result; 7 | use std::str::FromStr; 8 | use domain::bits::message::{MessageBuf, RecordSection}; 9 | use domain::bits::name::{DNameBuf, DNameSlice}; 10 | use domain::iana::{Class, Rtype}; 11 | use domain::resolv::{ResolvConf, Resolver}; 12 | 13 | 14 | //------------ Options ------------------------------------------------------ 15 | 16 | struct Options { 17 | // @server 18 | // -b address 19 | // -c class Class as string 20 | // -f filename 21 | // -k filename 22 | // -m 23 | // -p port# 24 | // -q name 25 | // -t type 26 | // -x addr 27 | // -y [hmac:name:key] 28 | // -4 29 | // -6 30 | name: String, // name 31 | qtype: String, // type Type as string 32 | qclass: String, // class 33 | // queryopt... 34 | 35 | conf: ResolvConf, 36 | } 37 | 38 | impl Options { 39 | fn new() -> Options { 40 | let mut conf = ResolvConf::new(); 41 | let _ = conf.parse_file("/etc/resolv.conf"); 42 | conf.finalize(); 43 | conf.options.use_vc = true; 44 | Options { 45 | name: String::new(), 46 | qtype: String::new(), // default depends on name. 47 | qclass: "IN".to_string(), 48 | conf: conf, 49 | } 50 | } 51 | 52 | fn from_args() -> Options { 53 | let mut res = Options::new(); 54 | res.parse(); 55 | res 56 | } 57 | 58 | fn parse(&mut self) { 59 | use argparse::{ArgumentParser, Store}; 60 | 61 | let mut parser = ArgumentParser::new(); 62 | 63 | parser.refer(&mut self.name) 64 | .add_argument("name", Store, "name of the resource record"); 65 | parser.refer(&mut self.qtype) 66 | .add_argument("type", Store, "query type"); 67 | parser.refer(&mut self.qclass) 68 | .add_argument("class", Store, "query class"); 69 | 70 | parser.parse_args_or_exit(); 71 | } 72 | } 73 | 74 | impl Options { 75 | fn name(&self) -> Result { 76 | if self.name.is_empty() { 77 | Ok(DNameSlice::root().to_owned()) 78 | } 79 | else { 80 | let mut res = try!(DNameBuf::from_str(&self.name)); 81 | res.append_root().unwrap(); 82 | Ok(res) 83 | } 84 | } 85 | 86 | fn qtype(&self) -> Result { 87 | if self.qtype.is_empty() { 88 | Ok(if self.name.is_empty() { Rtype::Ns } else { Rtype::A }) 89 | } 90 | else { 91 | Ok(try!(Rtype::from_str(&self.qtype))) 92 | } 93 | } 94 | 95 | fn qclass(&self) -> Result { 96 | Ok(Class::In) 97 | } 98 | 99 | fn conf(&self) -> &ResolvConf { &self.conf } 100 | } 101 | 102 | 103 | //------------ Error and Result --------------------------------------------- 104 | 105 | type Error = Box; 106 | 107 | type Result = result::Result; 108 | 109 | 110 | //------------ Processing Steps --------------------------------------------- 111 | 112 | fn query(options: Options) -> MessageBuf { 113 | Resolver::run_with_conf(options.conf().clone(), |resolv| { 114 | resolv.query((options.name().unwrap(), options.qtype().unwrap(), 115 | options.qclass().unwrap())) 116 | }).unwrap() 117 | } 118 | 119 | fn print_result(response: MessageBuf) { 120 | println!(";; Got answer:"); 121 | println!(";; ->>HEADER<<- opcode: {}, status: {}, id: {}", 122 | response.header().opcode(), response.header().rcode(), 123 | response.header().id()); 124 | print!(";; flags:"); 125 | if response.header().qr() { print!(" qr"); } 126 | if response.header().aa() { print!(" aa"); } 127 | if response.header().tc() { print!(" tc"); } 128 | if response.header().rd() { print!(" rd"); } 129 | if response.header().ra() { print!(" ra"); } 130 | if response.header().ad() { print!(" ad"); } 131 | if response.header().cd() { print!(" cd"); } 132 | println!("; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}", 133 | response.counts().qdcount(), response.counts().ancount(), 134 | response.counts().nscount(), response.counts().arcount()); 135 | println!(""); 136 | 137 | let mut question = response.question(); 138 | if response.counts().qdcount() > 0 { 139 | println!(";; QUESTION SECTION"); 140 | for item in &mut question { 141 | let item = item.unwrap(); 142 | println!("; {}\t\t{}\t{}", item.qname(), 143 | item.qclass(), item.qtype()); 144 | } 145 | println!(""); 146 | } 147 | 148 | let mut answer = question.answer().unwrap(); 149 | if response.counts().ancount() > 0 { 150 | println!(";; ANSWER SECTION"); 151 | print_records(&mut answer); 152 | println!(""); 153 | } 154 | 155 | let mut authority = answer.next_section().unwrap().unwrap(); 156 | if response.counts().nscount() > 0 { 157 | println!(";; AUTHORITY SECTION"); 158 | print_records(&mut authority); 159 | println!(""); 160 | } 161 | 162 | let mut additional = authority.next_section().unwrap().unwrap(); 163 | if response.counts().arcount() > 0 { 164 | println!(";; ADDITIONAL SECTION"); 165 | print_records(&mut additional); 166 | println!(""); 167 | } 168 | } 169 | 170 | fn print_records(section: &mut RecordSection) { 171 | for record in section { 172 | println!("{}", record.unwrap()); 173 | } 174 | } 175 | 176 | 177 | //------------ Main Function ------------------------------------------------ 178 | 179 | fn main() { 180 | let options = Options::from_args(); 181 | let response = query(options); 182 | let len = response.len(); 183 | print_result(response); 184 | println!(";; Query time: not yet available."); 185 | println!(";; SERVER: we don't currently know."); 186 | println!(";; WHEN: not yet available."); 187 | println!(";; MSG SIZE rcvd: {} bytes", len); 188 | println!(""); 189 | } 190 | -------------------------------------------------------------------------------- /examples/lookup.rs: -------------------------------------------------------------------------------- 1 | extern crate domain; 2 | 3 | use std::env; 4 | //use std::io; 5 | use std::net::IpAddr; 6 | use std::str::FromStr; 7 | use domain::bits::DNameBuf; 8 | use domain::resolv::{Resolver, ResolvConf}; 9 | use domain::resolv::conf::ServerMode; 10 | use domain::resolv::lookup::{lookup_addr, lookup_host}; 11 | 12 | 13 | fn forward(name: DNameBuf, conf: ResolvConf) { 14 | match Resolver::run_with_conf(conf, |resolv| lookup_host(resolv, &name)) { 15 | Ok(result) => { 16 | if name != result.canonical_name() { 17 | println!("{} is an alias for {}", 18 | name, result.canonical_name()); 19 | } 20 | for addr in result.iter() { 21 | println!("{} has address {}", result.canonical_name(), addr); 22 | } 23 | }, 24 | Err(err) => { 25 | println!("Error: {:?}", err); 26 | } 27 | } 28 | } 29 | 30 | fn reverse(addr: IpAddr, conf: ResolvConf) { 31 | match Resolver::run_with_conf(conf, |resolv| lookup_addr(resolv, addr)) { 32 | Ok(result) => { 33 | println!("Success:"); 34 | for name in result.iter() { 35 | println!("Host {} has domain name pointer {}", addr, name); 36 | } 37 | }, 38 | Err(err) => { 39 | println!("Error: {}", err); 40 | } 41 | } 42 | } 43 | 44 | fn set_tcp_mode(conf: &mut ResolvConf, mode: ServerMode) { 45 | for server in &mut conf.servers { 46 | server.tcp = mode; 47 | } 48 | } 49 | 50 | fn parse_queryopt(conf: &mut ResolvConf, arg: &str) { 51 | match arg { 52 | "+vc" => conf.options.use_vc = true, 53 | "+tcpsgl" => set_tcp_mode(conf, ServerMode::SingleRequest), 54 | "+tcpseq" => set_tcp_mode(conf, ServerMode::Sequential), 55 | "+tcpmul" => set_tcp_mode(conf, ServerMode::Multiplex), 56 | _ => { 57 | println!("Warning: ignoring unknown query option {}", arg); 58 | } 59 | } 60 | } 61 | 62 | fn main() { 63 | let mut conf = ResolvConf::default(); 64 | let mut names = Vec::new(); 65 | for arg in env::args().skip(1) { 66 | if arg.starts_with('+') { 67 | parse_queryopt(&mut conf, &arg) 68 | } 69 | else { 70 | names.push(arg) 71 | } 72 | } 73 | if names.is_empty() { 74 | println!("Usage: host [OPTIONS] "); 75 | return; 76 | } 77 | 78 | for name in names { 79 | if let Ok(addr) = IpAddr::from_str(&name) { 80 | reverse(addr, conf.clone()) 81 | } 82 | else if let Ok(name) = DNameBuf::from_str(&name) { 83 | forward(name, conf.clone()) 84 | } 85 | else { 86 | println!("Not a domain name: {}", name) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /examples/rusthome.rs: -------------------------------------------------------------------------------- 1 | //! Download and print the Rust homepage. 2 | //! 3 | //! This is the [toy HTTP+TLS client] example from the [futures tutorial] 4 | //! extended to use our resolver. 5 | //! 6 | //! [toy HTTP+TLS client]: https://tokio.rs/docs/getting-started/tls/ 7 | //! [futures tutorial]: https://tokio.rs/docs/getting-started/futures/ 8 | 9 | extern crate futures; 10 | extern crate native_tls; 11 | extern crate tokio_core; 12 | extern crate tokio_io; 13 | extern crate tokio_tls; 14 | extern crate domain; 15 | 16 | use std::io; 17 | use std::str::FromStr; 18 | 19 | use futures::Future; 20 | use native_tls::TlsConnector; 21 | use tokio_core::net::TcpStream; 22 | use tokio_core::reactor::Core; 23 | use tokio_tls::TlsConnectorExt; 24 | use domain::bits::DNameBuf; 25 | use domain::resolv::Resolver; 26 | use domain::resolv::lookup::lookup_host; 27 | 28 | #[allow(unknown_lints, string_lit_as_bytes)] 29 | fn main() { 30 | let mut core = Core::new().unwrap(); 31 | let handle = core.handle(); 32 | let resolver = Resolver::new(&handle); 33 | let addr = lookup_host(resolver, DNameBuf::from_str("www.rust-lang.org") 34 | .unwrap()).map_err(Into::into); 35 | let cx = TlsConnector::builder().unwrap().build().unwrap(); 36 | let socket = addr.and_then(|addr| { 37 | TcpStream::connect(&addr.port_iter(443).next().unwrap(), &handle) 38 | }); 39 | 40 | let tls_handshake = socket.and_then(|socket| { 41 | let tls = cx.connect_async("www.rust-lang.org", socket); 42 | tls.map_err(|e| { 43 | io::Error::new(io::ErrorKind::Other, e) 44 | }) 45 | }); 46 | let request = tls_handshake.and_then(|socket| { 47 | tokio_io::io::write_all(socket, "\ 48 | GET / HTTP/1.0\r\n\ 49 | Host: www.rust-lang.org\r\n\ 50 | \r\n\ 51 | ".as_bytes()) 52 | }); 53 | let response = request.and_then(|(socket, _request)| { 54 | tokio_io::io::read_to_end(socket, Vec::new()) 55 | }); 56 | 57 | let (_socket, data) = core.run(response).unwrap(); 58 | println!("{}", String::from_utf8_lossy(&data)); 59 | } 60 | -------------------------------------------------------------------------------- /src/bits/mod.rs: -------------------------------------------------------------------------------- 1 | //! DNS data. 2 | //! 3 | //! This module provides types and traits for working with DNS data as well 4 | //! as parsing and composing wire-format DNS messages. 5 | //! 6 | //! # Working with DNS Data 7 | //! 8 | //! The module contains abstractions for two concepts used in DNS data: 9 | //! domain names and character strings. In both cases, the supplied types 10 | //! internally contain the binary data and work directly on it. Similar 11 | //! to raw bytes slices, there types for borrowed and owned domain names 12 | //! and character strings where the owned type derefs to the borrowed one. 13 | //! For domain names, these types are [`DNameSlice`] and [`DNameBuf`]; 14 | //! for character strings [`CharStr`] and [`CharStrBuf`]. 15 | //! 16 | //! For domain names there is a third variant, [`ParsedDName`]. This type is 17 | //! necessary to represent compressed names where the remainder of a name is 18 | //! to be found elsewhere in the message. It avoids allocations when access 19 | //! to the entire name isn’t necessary. 20 | //! 21 | //! Traits are used when constructing composite types to allow them to work 22 | //! on borrowed and owned data as well as on parsed domain names. For 23 | //! character strings and raw bytes data, `AsRef` and `AsRef<[u8]>` 24 | //! are being used. For domain names, there is a separate trait, [`DName`] 25 | //! with the same purpose. However, its functionality is limited to the 26 | //! what parsed domain names can provide. 27 | //! 28 | //! A number of composite types are already defined: [`Question`] for 29 | //! the questions of a query, [`Record`] for resource records. 30 | //! 31 | //! Instead of having one big enum, the data of resource records is kept 32 | //! generic through two traits: [`RecordData`] provides functions common to 33 | //! all variants of record data types while [`ParsedRecordData`] adds 34 | //! the ability to construct a value from a wire-format message for those 35 | //! variants that can use borrowed data and parsed domain names. The actual 36 | //! types implementing these traits can by found in the crate’s [rdata] 37 | //! module. 38 | //! 39 | //! # Parsing and Composing Messages 40 | //! 41 | //! In order to easily distinguish the process of creating and disecting 42 | //! wire-format messages from working with master files, we use the term 43 | //! *parsing* and *composing* for reading from and writing to wire-format 44 | //! data. 45 | //! 46 | //! Both parsing and composing happen on bytes buffers. This seems to be a 47 | //! reasonably good choice given the relatively small size of DNS messages and 48 | //! the complexities introduced by name compression. The details are 49 | //! explained in the [parse] and [compose] sub-modules. Unless you are 50 | //! implementing your own resource record types, you are unlikely to ever 51 | //! having to deal with parsing and composing directly. 52 | //! 53 | //! Instead, the types [`Message`] and [`MessageBuilder`] are there to make 54 | //! parsing and constructing DNS messages easy. A [`Message`] takes the 55 | //! binary data of a DNS message and allows iterating over its four 56 | //! sections to look at the questions and resource records. Similarly, 57 | //! a [`MessageBuilder`] takes a bytes vector (or creates one for you) and 58 | //! has functionality to build the sections of the message step-by-step. 59 | //! 60 | //! [rdata]: ../rdata/index.html 61 | //! [compose]: compose/index.html 62 | //! [parse]: parse/index.html 63 | //! [`CharStr`]: charstr/struct.CharStr.html 64 | //! [`CharStrBuf`]: charstr/struct.CharStrBuf.html 65 | //! [`DName`]: name/trait.DName.html 66 | //! [`DNameBuf`]: name/struct.DNameBuf.html 67 | //! [`DNameSlice`]: name/struct.DNameSlice.html 68 | //! [`Message`]: message/struct.Message.html 69 | //! [`MessageBuilder`]: message_builder/struct.MessageBuilder.html 70 | //! [`ParsedDName`]: name/struct.ParsedDName.html 71 | //! [`ParsedRecordData`]: rdata/trait.ParsedRecordData.html 72 | //! [`Question`]: question/struct.Question.html 73 | //! [`Record`]: record/struct.Record.html 74 | //! [`RecordData`]: rdata/trait.RecordData.html 75 | 76 | 77 | //--- Re-exports 78 | 79 | pub use self::charstr::{CharStr, CharStrBuf}; 80 | pub use self::compose::{Composable, Composer, ComposeError, ComposeMode, 81 | ComposeResult, ComposeSnapshot}; 82 | pub use self::header::{Header, HeaderCounts, HeaderSection}; 83 | pub use self::message::{Message, MessageBuf}; 84 | pub use self::message_builder::{MessageBuilder, AnswerBuilder, 85 | AuthorityBuilder, AdditionalBuilder}; 86 | pub use self::name::{DName, DNameBuf, DNameSlice, ParsedDName}; 87 | pub use self::parse::{Parser, ParseError, ParseResult}; 88 | pub use self::question::Question; 89 | pub use self::rdata::{GenericRecordData, ParsedRecordData, RecordData}; 90 | pub use self::record::{GenericRecord, Record}; 91 | 92 | 93 | //--- Modules 94 | 95 | pub mod charstr; 96 | pub mod compose; 97 | pub mod header; 98 | pub mod message; 99 | pub mod message_builder; 100 | pub mod name; 101 | pub mod opt; 102 | pub mod parse; 103 | pub mod question; 104 | pub mod rdata; 105 | pub mod record; 106 | 107 | -------------------------------------------------------------------------------- /src/bits/name/builder.rs: -------------------------------------------------------------------------------- 1 | //! Building an owned domain name, 2 | 3 | use super::{DNameBuf, DNameSlice, FromStrError}; 4 | use super::plain::buf_from_vec_unsafe; 5 | 6 | //------------ DNameBuilder -------------------------------------------------- 7 | 8 | /// Builds an owned domain step by step from bytes. 9 | /// 10 | /// This type allows to build a `DNameBuf` slowly by feeding bytes. It is 11 | /// used by the master format scanner. 12 | #[derive(Clone, Debug)] 13 | pub struct DNameBuilder<'a>(DNameBuildInto<'a, Vec>); 14 | 15 | impl<'a> DNameBuilder<'a> { 16 | /// Create a new domain name builder. 17 | /// 18 | /// If `origin` is given, it will be appened to the resulting domain 19 | /// name if it is relative. 20 | pub fn new(origin: Option<&'a DNameSlice>) -> Self { 21 | DNameBuilder(DNameBuildInto::new(Vec::new(), origin)) 22 | } 23 | 24 | /// Pushes an octet to the end of the builder. 25 | pub fn push(&mut self, b: u8) -> Result<(), FromStrError> { 26 | self.0.push(b) 27 | } 28 | 29 | /// Pushes a label end to the builder. 30 | pub fn end_label(&mut self) { 31 | self.0.end_label() 32 | } 33 | 34 | /// Extracts the finished domain name from the builder. 35 | pub fn done(self) -> Result { 36 | let res = try!(self.0.done()); 37 | Ok(unsafe { buf_from_vec_unsafe(res) }) 38 | } 39 | } 40 | 41 | 42 | //------------ DNameBuildInto ------------------------------------------------ 43 | 44 | /// A type for iteratively pushing a domain name into a bytes vec. 45 | #[derive(Clone, Debug)] 46 | pub struct DNameBuildInto<'a, V: AsMut>> { 47 | target: V, 48 | 49 | /// The position in `buf` where we start. 50 | start: usize, 51 | 52 | /// The position of the last label head. 53 | head: usize, 54 | 55 | /// The origin to append to the name if it is relative. 56 | origin: Option<&'a DNameSlice>, 57 | 58 | /// The name is absolute and we are done. 59 | absolute: bool, 60 | } 61 | 62 | impl<'a, V: AsMut>> DNameBuildInto<'a, V> { 63 | /// Creates a new domain name builder. 64 | /// 65 | /// The domain name will be appended to the end of `target`. 66 | /// 67 | /// If `origin` is given, it will be appened to the resulting domain 68 | /// name if it is relative. 69 | pub fn new(mut target: V, origin: Option<&'a DNameSlice>) 70 | -> Self { 71 | let len = target.as_mut().len(); 72 | let mut res = DNameBuildInto { target: target, start: len, head: len, 73 | origin: origin, absolute: false }; 74 | res.target.as_mut().push(0); 75 | res 76 | } 77 | 78 | /// Appends an octet to the end of the domain name. 79 | pub fn push(&mut self, b: u8) -> Result<(), FromStrError> { 80 | if self.absolute { 81 | Err(FromStrError::EmptyLabel) 82 | } 83 | else if self.target.as_mut().len() - self.head == 63 { 84 | Err(FromStrError::LongLabel) 85 | } 86 | else if self.target.as_mut().len() - self.start == 254 { 87 | Err(FromStrError::LongName) 88 | } 89 | else { 90 | self.target.as_mut().push(b); 91 | Ok(()) 92 | } 93 | } 94 | 95 | /// Ends a label. 96 | pub fn end_label(&mut self) { 97 | if !self.absolute { 98 | if self.target.as_mut().len() == self.head + 1 { 99 | // Empty label is root label. We are done here. 100 | self.absolute = true 101 | } 102 | else { 103 | self.target.as_mut()[self.head] 104 | = (self.target.as_mut().len() - self.head - 1) as u8; 105 | self.head = self.target.as_mut().len(); 106 | self.target.as_mut().push(0); 107 | } 108 | } 109 | } 110 | 111 | /// Finishes building the name and extracts the target. 112 | pub fn done(mut self) -> Result { 113 | if !self.absolute && self.target.as_mut().len() > self.head + 1 { 114 | self.target.as_mut()[self.head] 115 | = (self.target.as_mut().len() - self.head - 1) as u8; 116 | if let Some(origin) = self.origin { 117 | self.target.as_mut().extend(origin.as_bytes()); 118 | if self.target.as_mut().len() - self.start > 255 { 119 | return Err(FromStrError::LongName) 120 | } 121 | } 122 | else { 123 | return Err(FromStrError::RelativeName) 124 | } 125 | } 126 | Ok(self.target) 127 | } 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/bits/name/dname.rs: -------------------------------------------------------------------------------- 1 | //! A trait for all domain name types. 2 | 3 | use std::borrow::Cow; 4 | use super::super::{Composer, ComposeResult}; 5 | use super::{DNameSlice, NameLabels, NameLabelettes}; 6 | 7 | 8 | //------------ DName --------------------------------------------------------- 9 | 10 | /// A trait implemented by all domain name types. 11 | /// 12 | /// The purpose of the trait is to allow building composite types that are 13 | /// generic over all possible variants of domain names. In particular, 14 | /// `DName` is implemented for [`&DNameSlice`] for references to uncompressed 15 | /// domain names, [`DNameBuf`] for owned uncompressed domain names, and 16 | /// [`ParsedDName`] for domain names parsed from DNS messages. 17 | /// 18 | /// If you don’t need to include [`ParsedDName`], you might want your type 19 | /// to be generic over `AsRef` instead as this allows for the 20 | /// full range of functionality provided by [`DNameSlice`]. 21 | /// 22 | /// [`&DNameSlice`]: struct.DNameSlice.html 23 | /// [`DNameBuf`]: struct.DNameBuf.html 24 | /// [`ParsedDName`]: struct.ParsedDName.html 25 | pub trait DName: Sized { 26 | /// Converts the name into an uncompressed name. 27 | /// 28 | /// Since unpacking parsed domain names may need allocations to collect 29 | /// the labels, the return value is a cow. This cow will, however, be of 30 | /// the borrowed variant whenever possible. 31 | fn to_cow(&self) -> Cow; 32 | 33 | /// Returns an iterator over the labels of the domain name. 34 | fn labels(&self) -> NameLabels; 35 | 36 | /// Returns an iterator over the labelettes of the domain name. 37 | /// 38 | /// See [`Labelette`] for a discussion of what exactly labelettes are. 39 | /// 40 | /// [`Labelette`]: struct.Labelette.html 41 | fn labelettes(&self) -> NameLabelettes { 42 | NameLabelettes::new(self.labels()) 43 | } 44 | 45 | /// Appends the name to the end of a composition. 46 | fn compose>(&self, mut composer: C) 47 | -> ComposeResult<()> { 48 | composer.as_mut().compose_dname(self) 49 | } 50 | 51 | /// Appends the name to the end of a composition using name compression. 52 | fn compose_compressed>(&self, mut composer: C) 53 | -> ComposeResult<()> { 54 | composer.as_mut().compose_dname_compressed(self) 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/bits/name/mod.rs: -------------------------------------------------------------------------------- 1 | //! Domain names. 2 | //! 3 | //! This module contains various types for working with domain names. 4 | //! 5 | //! Domain names are a sequence of *labels.* For the most part, labels are 6 | //! in turn a sequence of up to 63 octets. While they are limited to ASCII 7 | //! by convention, all values are allowed. In their wire-format representation 8 | //! labels are prefixed with an octet containing the the number of octets 9 | //! in the label. The labels in a domain name are nominally arranged 10 | //! backwards. That is, the ‘most significant’ label is the last one. In an 11 | //! *absolute* domain name, this last label is an empty label, often called 12 | //! the *root label.* Only absolute names can appear inside DNS messages. 13 | //! 14 | //! There are two twists to this: One are binary labels which essentially 15 | //! encode a sequence of one-bit labels, are somewhat esoteric, and have been 16 | //! declared historic. The other is name compression. In order to save 17 | //! space in DNS messages (which were originally limited to 512 bytes for 18 | //! most cases), a name can end in a pointer to another name stored 19 | //! elsewhere in the message. This makes lazy message parsing somewhat 20 | //! difficult since you need to carry around a reference to the original 21 | //! message until actual parsing happens. 22 | //! 23 | //! This is why there are three types for domain names in this module. Two 24 | //! types represent uncompressed domain names encoded in their wire format 25 | //! atop a bytes sequence. The [`DNameSlice`] type is a slice of a domain 26 | //! name akin to a `[u8]`. It is an unsized type and will have to be used 27 | //! behind a pointer, typically a reference. The [`DNameBuf`] type acts as 28 | //! its owned companion. Similar to the relationship between `[u8]` and a 29 | //! `Vec` it derefs to a [`DNameSlice`] and provides facilities to 30 | //! manipulate domain names. Both types can contain either absolute or 31 | //! relative domain names. 32 | //! 33 | //! A compressed domain name can only occur in a parsed DNS message. 34 | //! Accordingly, its type is called [`ParsedDName`]. It internally holds a 35 | //! reference to the message it was parsed from. There’s only two things you 36 | //! can do with a parsed domain name: convert it into a regular domain name 37 | //! and iterate over its labels. Luckily, though, the latter is good enough 38 | //! for comparing them to other domain names. 39 | //! 40 | //! Creating data structures that can use both [`DNameSlice`] and [`DNameBuf`] 41 | //! can be achieved by being generic over `AsRef` as `AsRef` is 42 | //! implemented both for `&DNameSlice` and `DNameBuf`. In order to allow 43 | //! types that allow [`ParsedDName`] as well, there is an additional trait 44 | //! [`DName`]. Naturally, the functionality provided by it is limited to 45 | //! what [`ParsedDName`] can do: conversion into a regular domain name and 46 | //! iteration over labels. 47 | //! 48 | //! # TODO 49 | //! 50 | //! - Implement an optimization where there is an optional first byte with 51 | //! the unallocated label type 0b10 that indicates whether the name is 52 | //! absolute or relative (ie., 0x80 means absolute and 0x81 relative and 53 | //! everything else means this really is the first byte of the domain 54 | //! name). 55 | //! 56 | //! [`DName`]: trait.DName.html 57 | //! [`DNameSlice`]: struct.DNameSlice.html 58 | //! [`DNameBuf`]: struct.DNameBuf.html 59 | //! [`ParsedDName`]: struct.ParsedDName.html 60 | 61 | pub use self::builder::{DNameBuilder, DNameBuildInto}; 62 | pub use self::dname::DName; 63 | pub use self::iter::{NameLabels, NameLabelettes}; 64 | pub use self::label::{Label, LabelBuf, LabelContent, Labelette, LabelIter}; 65 | pub use self::parsed::ParsedDName; 66 | pub use self::plain::{DNameBuf, DNameSlice, FromStrError, PushError, 67 | StripSuffixError}; 68 | 69 | mod builder; 70 | mod dname; 71 | mod from_str; 72 | mod iter; 73 | mod label; 74 | mod parsed; 75 | mod plain; 76 | 77 | -------------------------------------------------------------------------------- /src/bits/opt/mod.rs: -------------------------------------------------------------------------------- 1 | //! Record data for OPT records. 2 | //! 3 | //! OPT records are meta records used by EDNS to convey additional data about 4 | //! clients, servers, and the query being performed. Because these records are 5 | //! fundamental for modern DNS operations, they are here instead of in the 6 | //! `rdata` module and the types defined for operating on them differ from 7 | //! how other record types are handled. 8 | 9 | use std::marker::PhantomData; 10 | use ::iana::{OptionCode, Rtype}; 11 | use super::{Composer, ComposeResult, ParsedRecordData, Parser, ParseResult, 12 | RecordData}; 13 | 14 | 15 | pub mod rfc5001; 16 | pub mod rfc6975; 17 | pub mod rfc7314; 18 | pub mod rfc7828; 19 | pub mod rfc7830; 20 | pub mod rfc7871; 21 | pub mod rfc7873; 22 | pub mod rfc7901; 23 | pub mod rfc8145; 24 | 25 | 26 | //------------ Opt ----------------------------------------------------------- 27 | 28 | #[derive(Clone, Debug)] 29 | pub struct Opt<'a>(Parser<'a>); 30 | 31 | impl<'a> Opt<'a> { 32 | pub fn iter>(&self) -> OptIter<'a, O> { 33 | OptIter::new(self.0.clone()) 34 | } 35 | } 36 | 37 | impl<'a> RecordData for Opt<'a> { 38 | fn rtype(&self) -> Rtype { 39 | Rtype::Opt 40 | } 41 | 42 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 43 | // Technically, there shouldn’t be name compression in OPT record 44 | // data. So we should be fine just copying the data verbatim. 45 | target.as_mut().compose_bytes(self.0.bytes()) 46 | } 47 | } 48 | 49 | 50 | impl<'a> ParsedRecordData<'a> for Opt<'a> { 51 | fn parse(rtype: Rtype, parser: &mut Parser<'a>) 52 | -> ParseResult> { 53 | if rtype == Rtype::Opt { 54 | Ok(Some(Opt(parser.clone()))) 55 | } 56 | else { 57 | Ok(None) 58 | } 59 | } 60 | } 61 | 62 | 63 | //------------ OptIter ------------------------------------------------------- 64 | 65 | #[derive(Clone, Debug)] 66 | pub struct OptIter<'a, O: ParsedOptData<'a>> { 67 | parser: Parser<'a>, 68 | marker: PhantomData 69 | } 70 | 71 | impl<'a, O: ParsedOptData<'a>> OptIter<'a, O> { 72 | fn new(parser: Parser<'a>) -> Self { 73 | OptIter { parser, marker: PhantomData } 74 | } 75 | } 76 | 77 | impl<'a, O: ParsedOptData<'a>> Iterator for OptIter<'a, O> { 78 | type Item = ParseResult; 79 | 80 | fn next(&mut self) -> Option { 81 | while self.parser.remaining() > 0 { 82 | match self.next_step() { 83 | Ok(Some(res)) => return Some(Ok(res)), 84 | Ok(None) => { } 85 | Err(err) => return Some(Err(err)), 86 | } 87 | } 88 | None 89 | } 90 | } 91 | 92 | impl<'a, O: ParsedOptData<'a>> OptIter<'a, O> { 93 | fn next_step(&mut self) -> ParseResult> { 94 | let code = self.parser.parse_u16()?.into(); 95 | let len = self.parser.parse_u16()? as usize; 96 | self.parser.set_limit(len)?; 97 | O::parse(code, &mut self.parser) 98 | } 99 | } 100 | 101 | 102 | //------------ OptData ------------------------------------------------------- 103 | 104 | pub trait OptData: Sized { 105 | fn compose>(&self, target: C) -> ComposeResult<()>; 106 | } 107 | 108 | 109 | pub trait ParsedOptData<'a>: OptData { 110 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 111 | -> ParseResult>; 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/bits/opt/rfc5001.rs: -------------------------------------------------------------------------------- 1 | /// EDNS0 Options from RFC 5001. 2 | 3 | use std::fmt; 4 | use ::bits::{Composer, ComposeResult, Parser, ParseResult}; 5 | use ::iana::OptionCode; 6 | use super::{OptData, ParsedOptData}; 7 | 8 | 9 | //------------ Nsid ---------------------------------------------------------/ 10 | 11 | /// The Name Server Identifier (NSID) Option. 12 | /// 13 | /// Specified in RFC 5001. 14 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 15 | pub struct Nsid>(B); 16 | 17 | impl> Nsid { 18 | pub fn new(data: B) -> Self { 19 | Nsid(data) 20 | } 21 | } 22 | 23 | impl> OptData for Nsid { 24 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 25 | assert!(self.0.as_ref().len() < ::std::u16::MAX as usize); 26 | target.as_mut().compose_u16(OptionCode::Nsid.to_int())?; 27 | target.as_mut().compose_u16(self.0.as_ref().len() as u16)?; 28 | target.as_mut().compose_bytes(self.0.as_ref()) 29 | } 30 | } 31 | 32 | impl<'a> ParsedOptData<'a> for Nsid<&'a [u8]> { 33 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 34 | -> ParseResult> { 35 | if let OptionCode::Nsid = code { 36 | parser.parse_remaining().map(|bytes| Some(Nsid(bytes))) 37 | } 38 | else { 39 | Ok(None) 40 | } 41 | } 42 | } 43 | 44 | impl> fmt::Display for Nsid { 45 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 46 | // RFC 5001 § 2.4: 47 | // | User interfaces MUST read and write the contents of the NSID 48 | // | option as a sequence of hexadecimal digits, two digits per 49 | // | payload octet. 50 | for v in self.0.as_ref() { 51 | write!(f, "{:X}", *v)? 52 | } 53 | Ok(()) 54 | } 55 | } 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/bits/opt/rfc6975.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 6975. 2 | 3 | use std::{ops, slice}; 4 | use ::bits::{Composer, ComposeResult, Parser, ParseResult}; 5 | use ::iana::{OptionCode, SecAlg}; 6 | use super::{OptData, ParsedOptData}; 7 | 8 | 9 | 10 | //------------ SecAlgs ------------------------------------------------------- 11 | 12 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 13 | pub struct SecAlgs>(B); 14 | 15 | impl> SecAlgs { 16 | pub fn iter(&self) -> SecAlgsIter { 17 | SecAlgsIter(self.0.as_ref().iter()) 18 | } 19 | 20 | fn compose>(&self, mut target: C, code: OptionCode) 21 | -> ComposeResult<()> { 22 | assert!(self.0.as_ref().len() <= ::std::u16::MAX as usize); 23 | target.as_mut().compose_u16(code.into())?; 24 | target.as_mut().compose_u16(self.0.as_ref().len() as u16)?; 25 | target.as_mut().compose_bytes(self.0.as_ref()) 26 | } 27 | } 28 | 29 | impl<'a> SecAlgs<&'a [u8]> { 30 | fn parse(wanted: OptionCode, code: OptionCode, 31 | parser: &mut Parser<'a>, 32 | wrap: F) -> ParseResult> 33 | where F: FnOnce(Self) -> T { 34 | if wanted == code { 35 | parser.parse_remaining().map(|bytes| Some(wrap(SecAlgs(bytes)))) 36 | } 37 | else { 38 | Ok(None) 39 | } 40 | } 41 | } 42 | 43 | impl SecAlgs> { 44 | pub fn push(&mut self, alg: SecAlg) { 45 | self.0.push(alg.into()) 46 | } 47 | } 48 | 49 | 50 | //------------ SecAlgsIter --------------------------------------------------- 51 | 52 | pub struct SecAlgsIter<'a>(slice::Iter<'a, u8>); 53 | 54 | impl<'a> Iterator for SecAlgsIter<'a> { 55 | type Item = SecAlg; 56 | 57 | fn next(&mut self) -> Option { 58 | self.0.next().map(|x| SecAlg::from_int(*x)) 59 | } 60 | } 61 | 62 | 63 | //------------ A Macro to Make the Three Option ------------------------------ 64 | 65 | macro_rules! option_type { 66 | ( $name:ident ) => { 67 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 68 | pub struct $name>(SecAlgs); 69 | 70 | impl> $name { 71 | pub fn new(data: B) -> Self { 72 | $name(SecAlgs(data)) 73 | } 74 | } 75 | 76 | impl> ops::Deref for $name { 77 | type Target = SecAlgs; 78 | 79 | fn deref(&self) -> &Self::Target { 80 | &self.0 81 | } 82 | } 83 | 84 | impl> ops::DerefMut for $name { 85 | fn deref_mut(&mut self) -> &mut Self::Target { 86 | &mut self.0 87 | } 88 | } 89 | 90 | impl> AsRef> for $name { 91 | fn as_ref(&self) -> &SecAlgs { 92 | &self.0 93 | } 94 | } 95 | 96 | impl> AsMut> for $name { 97 | fn as_mut(&mut self) -> &mut SecAlgs { 98 | &mut self.0 99 | } 100 | } 101 | 102 | impl> OptData for $name { 103 | fn compose>(&self, target: C) 104 | -> ComposeResult<()> { 105 | self.0.compose(target, OptionCode::$name) 106 | } 107 | } 108 | 109 | impl<'a> ParsedOptData<'a> for $name<&'a [u8]> { 110 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 111 | -> ParseResult> { 112 | SecAlgs::parse(OptionCode::$name, code, parser, $name) 113 | } 114 | } 115 | } 116 | } 117 | 118 | 119 | //------------ Dau ----------------------------------------------------------- 120 | 121 | option_type!(Dau); 122 | 123 | 124 | //------------ Dhu ----------------------------------------------------------- 125 | 126 | option_type!(Dhu); 127 | 128 | 129 | //------------ N3u ----------------------------------------------------------- 130 | 131 | option_type!(N3u); 132 | 133 | -------------------------------------------------------------------------------- /src/bits/opt/rfc7314.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 7314 2 | 3 | use ::bits::{Composer, ComposeResult, Parser, ParseError, ParseResult}; 4 | use ::iana::OptionCode; 5 | use super::{OptData, ParsedOptData}; 6 | 7 | 8 | //------------ Expire -------------------------------------------------------- 9 | 10 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 11 | pub struct Expire(Option); 12 | 13 | impl Expire { 14 | pub fn new(expire: Option) -> Self { 15 | Expire(expire) 16 | } 17 | 18 | pub fn expire(&self) -> Option { 19 | self.0 20 | } 21 | } 22 | 23 | impl OptData for Expire { 24 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 25 | let target = target.as_mut(); 26 | target.compose_u16(OptionCode::EdnsExpire.into())?; 27 | match self.0 { 28 | Some(expire) => { 29 | target.compose_u16(4)?; 30 | target.compose_u32(expire) 31 | } 32 | None => { 33 | target.compose_u16(0) 34 | } 35 | } 36 | } 37 | } 38 | 39 | impl<'a> ParsedOptData<'a> for Expire { 40 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 41 | -> ParseResult> { 42 | if code != OptionCode::EdnsExpire { 43 | return Ok(None) 44 | } 45 | match parser.remaining() { 46 | 0 => Ok(Some(Self::new(None))), 47 | 4 => Ok(Some(Self::new(Some(parser.parse_u32()?)))), 48 | _ => Err(ParseError::FormErr) 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/bits/opt/rfc7828.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 7828 2 | 3 | use ::bits::{Composer, ComposeResult, Parser, ParseResult}; 4 | use ::iana::OptionCode; 5 | use super::{OptData, ParsedOptData}; 6 | 7 | 8 | //------------ TcpKeepalive -------------------------------------------------- 9 | 10 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 11 | pub struct TcpKeepalive(u16); 12 | 13 | impl TcpKeepalive { 14 | pub fn new(timeout: u16) -> Self { 15 | TcpKeepalive(timeout) 16 | } 17 | 18 | pub fn timeout(&self) -> u16 { 19 | self.0 20 | } 21 | } 22 | 23 | impl OptData for TcpKeepalive { 24 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 25 | let target = target.as_mut(); 26 | target.compose_u16(OptionCode::EdnsTcpKeepalive.into())?; 27 | target.compose_u16(2)?; 28 | target.compose_u16(self.0) 29 | } 30 | } 31 | 32 | impl<'a> ParsedOptData<'a> for TcpKeepalive { 33 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 34 | -> ParseResult> { 35 | if code != OptionCode::EdnsTcpKeepalive { 36 | return Ok(None) 37 | } 38 | let timeout = parser.parse_u16()?; 39 | parser.exhausted()?; 40 | Ok(Some(Self::new(timeout))) 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/bits/opt/rfc7830.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 7830 2 | 3 | use rand::random; 4 | use ::bits::{Composer, ComposeResult, Parser, ParseResult}; 5 | use ::iana::OptionCode; 6 | use super::{OptData, ParsedOptData}; 7 | 8 | 9 | //------------ PaddingMode --------------------------------------------------- 10 | 11 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 12 | pub enum PaddingMode { 13 | Zero, 14 | Random, 15 | } 16 | 17 | 18 | //------------ Padding ------------------------------------------------------- 19 | 20 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 21 | pub struct Padding { 22 | len: u16, 23 | mode: PaddingMode 24 | } 25 | 26 | 27 | impl Padding { 28 | pub fn new(len: u16, mode: PaddingMode) -> Self { 29 | Padding { len, mode } 30 | } 31 | 32 | pub fn len(&self) -> u16 { 33 | self.len 34 | } 35 | 36 | pub fn mode(&self) -> PaddingMode { 37 | self.mode 38 | } 39 | } 40 | 41 | impl OptData for Padding { 42 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 43 | let target = target.as_mut(); 44 | target.compose_u16(OptionCode::Padding.into())?; 45 | target.compose_u16(self.len)?; 46 | match self.mode { 47 | PaddingMode::Zero => { 48 | target.compose_empty(self.len as usize) 49 | } 50 | PaddingMode::Random => { 51 | for _ in 0..self.len { 52 | target.compose_u8(random())? 53 | } 54 | Ok(()) 55 | } 56 | } 57 | } 58 | } 59 | 60 | impl<'a> ParsedOptData<'a> for Padding { 61 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 62 | -> ParseResult> { 63 | if code != OptionCode::Padding { 64 | return Ok(None) 65 | } 66 | Ok(Some(Padding::new(parser.remaining() as u16, PaddingMode::Zero))) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/bits/opt/rfc7871.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 7871 2 | 3 | use std::mem; 4 | use std::net::IpAddr; 5 | use ::bits::{Composer, ComposeResult, Parser, ParseError, ParseResult}; 6 | use ::iana::OptionCode; 7 | use super::{OptData, ParsedOptData}; 8 | 9 | 10 | //------------ ClientSubnet -------------------------------------------------- 11 | 12 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 13 | pub struct ClientSubnet { 14 | source_prefix_len: u8, 15 | scope_prefix_len: u8, 16 | addr: IpAddr, 17 | } 18 | 19 | 20 | impl ClientSubnet { 21 | pub fn new(source_prefix_len: u8, scope_prefix_len: u8, addr: IpAddr) 22 | -> ClientSubnet { 23 | ClientSubnet { source_prefix_len, scope_prefix_len, addr } 24 | } 25 | 26 | pub fn source_prefix_len(&self) -> u8 { self.source_prefix_len } 27 | pub fn scope_prefix_len(&self) -> u8 { self.scope_prefix_len } 28 | pub fn addr(&self) -> IpAddr { self.addr } 29 | } 30 | 31 | impl OptData for ClientSubnet { 32 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 33 | let target = target.as_mut(); 34 | target.compose_u16(OptionCode::EdnsClientSubnet.into())?; 35 | match self.addr { 36 | IpAddr::V4(addr) => { 37 | target.compose_u16(4 + 4)?; 38 | target.compose_u16(1)?; 39 | target.compose_u8(self.source_prefix_len)?; 40 | target.compose_u8(self.scope_prefix_len)?; 41 | target.compose_bytes(&addr.octets()) 42 | } 43 | IpAddr::V6(addr) => { 44 | target.compose_u16(16 + 4)?; 45 | target.compose_u16(2)?; 46 | target.compose_u8(self.source_prefix_len)?; 47 | target.compose_u8(self.scope_prefix_len)?; 48 | target.compose_bytes(&addr.octets()) 49 | } 50 | } 51 | } 52 | } 53 | 54 | impl<'a> ParsedOptData<'a> for ClientSubnet { 55 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 56 | -> ParseResult> { 57 | if code != OptionCode::EdnsClientSubnet { 58 | return Ok(None) 59 | } 60 | let family = parser.parse_u16()?; 61 | let source_prefix_len = parser.parse_u8()?; 62 | let scope_prefix_len = parser.parse_u8()?; 63 | let addr = match family { 64 | 1 => { 65 | let bytes: &[u8; 4] = unsafe { 66 | mem::transmute(parser.parse_bytes(4)?.as_ptr()) 67 | }; 68 | IpAddr::from(*bytes) 69 | } 70 | 2 => { 71 | let bytes: &[u8; 16] = unsafe { 72 | mem::transmute(parser.parse_bytes(16)?.as_ptr()) 73 | }; 74 | IpAddr::from(*bytes) 75 | } 76 | _ => return Err(ParseError::FormErr) 77 | }; 78 | parser.exhausted()?; 79 | Ok(Some(ClientSubnet::new(source_prefix_len, scope_prefix_len, addr))) 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/bits/opt/rfc7873.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options form RFC 7873 2 | 3 | use std::mem; 4 | use ::bits::{Composer, ComposeResult, Parser, ParseResult}; 5 | use ::iana::OptionCode; 6 | use super::{OptData, ParsedOptData}; 7 | 8 | 9 | //------------ Cookie -------------------------------------------------------- 10 | 11 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 12 | pub struct Cookie([u8; 8]); 13 | 14 | impl Cookie { 15 | pub fn new(cookie: [u8; 8]) -> Self { 16 | Cookie(cookie) 17 | } 18 | 19 | pub fn cookie(&self) -> &[u8; 8] { 20 | &self.0 21 | } 22 | } 23 | 24 | impl OptData for Cookie { 25 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 26 | let target = target.as_mut(); 27 | target.compose_u16(OptionCode::Cookie.into())?; 28 | target.compose_u16(8)?; 29 | target.compose_bytes(&self.0[..]) 30 | } 31 | } 32 | 33 | impl<'a> ParsedOptData<'a> for Cookie { 34 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 35 | -> ParseResult> { 36 | if code != OptionCode::Cookie { 37 | return Ok(None) 38 | } 39 | let bytes: &[u8; 8] = unsafe { 40 | mem::transmute(parser.parse_bytes(8)?.as_ptr()) 41 | }; 42 | parser.exhausted()?; 43 | Ok(Some(Cookie::new(*bytes))) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/bits/opt/rfc7901.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 7901 2 | 3 | use ::bits::{Composer, ComposeError, ComposeResult, DName, ParsedDName, 4 | Parser, ParseResult}; 5 | use ::iana::OptionCode; 6 | use super::{OptData, ParsedOptData}; 7 | 8 | 9 | //------------ Chain -------------------------------------------------------- 10 | 11 | #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 12 | pub struct Chain(N); 13 | 14 | impl Chain { 15 | pub fn new(name: N) -> Self { 16 | Chain(name) 17 | } 18 | 19 | pub fn name(&self) -> &N { 20 | &self.0 21 | } 22 | } 23 | 24 | impl OptData for Chain { 25 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 26 | let target = target.as_mut(); 27 | target.compose_u16(OptionCode::Chain.into())?; 28 | let pos = target.pos(); 29 | target.compose_u16(0)?; 30 | target.compose_dname(&self.0)?; 31 | let len = target.pos() - pos; 32 | if len > ::std::u16::MAX as usize { 33 | return Err(ComposeError::SizeExceeded) 34 | } 35 | target.update_u16(pos, len as u16); 36 | Ok(()) 37 | } 38 | } 39 | 40 | impl<'a> ParsedOptData<'a> for Chain> { 41 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 42 | -> ParseResult> { 43 | if code != OptionCode::Chain { 44 | return Ok(None) 45 | } 46 | let name = ParsedDName::parse(parser)?; 47 | parser.exhausted()?; 48 | Ok(Some(Chain::new(name))) 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/bits/opt/rfc8145.rs: -------------------------------------------------------------------------------- 1 | //! EDNS Options from RFC 8145. 2 | 3 | use ::bits::{Composer, ComposeResult, Parser, ParseError, ParseResult}; 4 | use ::iana::OptionCode; 5 | use super::{OptData, ParsedOptData}; 6 | 7 | 8 | //------------ KeyTag ------------------------------------------------------- 9 | 10 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 11 | pub struct KeyTag>(B); 12 | 13 | impl> KeyTag { 14 | } 15 | 16 | impl<'a> KeyTag<&'a [u8]> { 17 | pub fn new(bytes: &'a [u8]) -> Self { 18 | KeyTag(bytes) 19 | } 20 | } 21 | 22 | impl KeyTag> { 23 | pub fn new() -> Self { 24 | KeyTag(Vec::new()) 25 | } 26 | 27 | pub fn push(&mut self, tag: u16) { 28 | if self.0.len() >= (0xFFFF - 2) { 29 | panic!("excessively large Keytag"); 30 | } 31 | self.0.push((tag & 0xFF00 >> 8) as u8); 32 | self.0.push((tag & 0xFF) as u8); 33 | } 34 | } 35 | 36 | impl> OptData for KeyTag { 37 | fn compose>(&self, mut target: C) -> ComposeResult<()> { 38 | assert!(self.0.as_ref().len() <= 0xFFFF); 39 | let target = target.as_mut(); 40 | target.compose_u16(OptionCode::EdnsKeyTag.into())?; 41 | target.compose_u16(self.0.as_ref().len() as u16)?; 42 | target.compose_bytes(&self.0.as_ref()) 43 | } 44 | } 45 | 46 | impl<'a> ParsedOptData<'a> for KeyTag<&'a [u8]> { 47 | fn parse(code: OptionCode, parser: &mut Parser<'a>) 48 | -> ParseResult> { 49 | if code != OptionCode::EdnsKeyTag { 50 | return Ok(None) 51 | } 52 | if parser.remaining() % 2 == 1 { 53 | Err(ParseError::FormErr) 54 | } 55 | else { 56 | Ok(Some(Self::new(parser.parse_remaining()?))) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/bits/parse.rs: -------------------------------------------------------------------------------- 1 | //! Parsing of DNS wire-format data. 2 | //! 3 | //! This module contains [`Parser`], the type wrapping the data of a DNS 4 | //! message for parsing, as well as the error and result types for parsing. 5 | //! You will only need to deal with parsing directly if you implement new 6 | //! record data types. Otherwise, the [`Message`] type wraps everyhing up 7 | //! in a nice, easy to use interface. 8 | //! 9 | //! [`Parser`]: struct.Parser.html 10 | //! [`Message`]: ../message/struct.Message.html 11 | 12 | use std::{error, fmt, io}; 13 | use byteorder::{BigEndian, ByteOrder}; 14 | 15 | 16 | //------------ Parser -------------------------------------------------------- 17 | 18 | /// A type wrapping DNS message data for parsing. 19 | /// 20 | /// Because of name compression, a full message needs to be available for 21 | /// parsing of DNS data. If you have received a message over the wire, you 22 | /// can use it to create a parser via the [`new()`] function. 23 | /// 24 | /// The parser then allows you to successively parse one item after the other 25 | /// out of the message via a few methods prefixed with `parse_`. Further 26 | /// methods are available to retrieve some information about the parser 27 | /// state, seek to a new position, or limit the amount of data the parser 28 | /// allows to retrieve. 29 | /// 30 | /// Parsers are `Clone`, so you can keep around a copy of a parser for later 31 | /// use. This is, for instance, done by [`ParsedDName`] in order to be able 32 | /// to rummage around the message bytes to find all its labels. 33 | /// 34 | /// [`new()`]: #method.new 35 | /// [`ParsedDName`]: ../name/struct.ParsedDName.html 36 | #[derive(Clone, Debug)] 37 | pub struct Parser<'a> { 38 | bytes: &'a [u8], 39 | pos: usize, 40 | limit: usize, 41 | } 42 | 43 | impl<'a> Parser<'a> { 44 | /// Creates a new parser atop a bytes slice. 45 | pub fn new(bytes: &'a [u8]) -> Self { 46 | Parser{limit: bytes.len(), bytes: bytes, pos: 0} 47 | } 48 | 49 | /// Limits the parser to `len` bytes from its current position. 50 | /// 51 | /// If the limit would be beyond the end of the parser, returns 52 | /// `Err(ParseError::UnexpectedEnd)`. 53 | pub fn set_limit(&mut self, len: usize) -> ParseResult<()> { 54 | let limit = self.pos + len; 55 | if len > self.bytes.len() { 56 | Err(ParseError::UnexpectedEnd) 57 | } 58 | else { 59 | self.limit = limit; 60 | Ok(()) 61 | } 62 | } 63 | 64 | /// Removes any limit from the parser. 65 | pub fn remove_limit(&mut self) { 66 | self.limit = self.bytes.len() 67 | } 68 | } 69 | 70 | impl<'a> Parser<'a> { 71 | /// Returns a reference to the complete message. 72 | /// 73 | /// The returned slice contains all bytes. It disregards the current 74 | /// position and any limit. 75 | pub fn bytes(&self) -> &'a [u8] { 76 | self.bytes 77 | } 78 | 79 | /// Returns the current parser position. 80 | /// 81 | /// This is the index in `self.bytes()` where the next octet would be 82 | /// read. 83 | pub fn pos(&self) -> usize { 84 | self.pos 85 | } 86 | 87 | /// Returns the number of bytes left to parse. 88 | /// 89 | /// If a limit is set, the returned number is up until that limit. 90 | pub fn remaining(&self) -> usize { 91 | self.limit - self.pos 92 | } 93 | 94 | /// Resets the position of the parser. 95 | /// 96 | /// The new position is relative to the beginning of the parser’s message. 97 | /// The function fails if the position is beyond the end of the message 98 | /// or, if a limit is set, beyond the limit. In either case, the 99 | /// function will return `Err(ParseError::UnexpectedEnd)`. 100 | pub fn seek(&mut self, pos: usize) -> ParseResult<()> { 101 | if pos > self.limit { 102 | Err(ParseError::UnexpectedEnd) 103 | } 104 | else { 105 | self.pos = pos; 106 | Ok(()) 107 | } 108 | } 109 | } 110 | 111 | impl<'a> Parser<'a> { 112 | /// Skips over `len` bytes. 113 | /// 114 | /// If this would go beyond the current limit or the end of the message, 115 | /// returns `Err(ParseError::UnexpectedEnd)`. 116 | pub fn skip(&mut self, len: usize) -> ParseResult<()> { 117 | self.parse_bytes(len).map(|_| ()) 118 | } 119 | 120 | /// Parses a bytes slice of the given length. 121 | /// 122 | /// The slice returned upon success references the parser’s message 123 | /// directly. The parser’s position is advanced until the end of the 124 | /// slice. 125 | /// 126 | /// The method will return `Err(ParseError::UnexpectedEnd)` if the 127 | /// length would take the parser beyond the current limit or the 128 | /// end of the message. 129 | pub fn parse_bytes(&mut self, len: usize) -> ParseResult<&'a [u8]> { 130 | let end = self.pos + len; 131 | if end > self.limit { 132 | return Err(ParseError::UnexpectedEnd) 133 | } 134 | let res = &self.bytes[self.pos..end]; 135 | self.pos = end; 136 | Ok(res) 137 | } 138 | 139 | pub fn parse_u8(&mut self) -> ParseResult { 140 | self.parse_bytes(1).map(|res| res[0]) 141 | } 142 | 143 | pub fn parse_u16(&mut self) -> ParseResult { 144 | self.parse_bytes(2).map(BigEndian::read_u16) 145 | } 146 | 147 | pub fn parse_u32(&mut self) -> ParseResult { 148 | self.parse_bytes(4).map(BigEndian::read_u32) 149 | } 150 | 151 | pub fn parse_remaining(&mut self) -> ParseResult<&'a [u8]> { 152 | let len = self.remaining(); 153 | self.parse_bytes(len) 154 | } 155 | 156 | /// Verifies that the parser is exhausted. 157 | /// 158 | /// Returns `Ok(())` if there are no remaining bytes in the parser or 159 | /// a form error otherwise. 160 | pub fn exhausted(&self) -> ParseResult<()> { 161 | if self.remaining() == 0 { 162 | Ok(()) 163 | } 164 | else { 165 | Err(ParseError::FormErr) 166 | } 167 | } 168 | } 169 | 170 | 171 | //------------ ParseError and ParseResult ----------------------------------- 172 | 173 | /// An error happening during parsing of wire-format DNS data. 174 | #[derive(Clone, Debug, PartialEq)] 175 | pub enum ParseError { 176 | /// The raw data ended unexpectedly in the middle of a structure. 177 | UnexpectedEnd, 178 | 179 | /// An unknown label type was encountered in a domain name. 180 | /// 181 | /// Several possible values for label types are not currently assigned 182 | /// (and likely never will). This is fatal since the label type defines 183 | /// how a label is parsed. 184 | UnknownLabel, 185 | 186 | /// A format error was encountered. 187 | FormErr, 188 | } 189 | 190 | impl error::Error for ParseError { 191 | fn description(&self) -> &str { 192 | use self::ParseError::*; 193 | 194 | match *self { 195 | UnexpectedEnd => "unexpected end of data", 196 | UnknownLabel => "unknown label type in domain name", 197 | FormErr => "format error", 198 | } 199 | } 200 | } 201 | 202 | impl From for io::Error { 203 | fn from(err: ParseError) -> io::Error { 204 | io::Error::new(io::ErrorKind::Other, Box::new(err)) 205 | } 206 | } 207 | 208 | impl fmt::Display for ParseError { 209 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 210 | error::Error::description(self).fmt(f) 211 | } 212 | } 213 | 214 | /// The result type for a `ParseError`. 215 | pub type ParseResult = Result; 216 | 217 | 218 | //============ Testing ====================================================== 219 | 220 | #[cfg(test)] 221 | mod test { 222 | use super::*; 223 | 224 | fn check(parser: &Parser, pos: usize, left: &[u8]) { 225 | assert_eq!(parser.pos(), pos); 226 | assert_eq!(parser.remaining(), left.len()); 227 | assert_eq!(&parser.bytes()[pos..], left) 228 | } 229 | 230 | #[test] 231 | fn parse_bytes_ok() { 232 | let mut parser = Parser::new(b"123456"); 233 | check(&parser, 0, b"123456"); 234 | assert_eq!(parser.parse_bytes(0).unwrap(), b""); 235 | check(&parser, 0, b"123456"); 236 | assert_eq!(parser.parse_bytes(4).unwrap(), b"1234"); 237 | check(&parser, 4, b"56"); 238 | assert_eq!(parser.parse_bytes(2).unwrap(), b"56"); 239 | check(&parser, 6, b""); 240 | assert_eq!(parser.parse_bytes(0).unwrap(), b""); 241 | check(&parser, 6, b""); 242 | } 243 | 244 | #[test] 245 | fn parse_bytes_err() { 246 | let mut parser = Parser::new(b"123456"); 247 | check(&parser, 0, b"123456"); 248 | assert_eq!(parser.parse_bytes(8), Err(ParseError::UnexpectedEnd)); 249 | check(&parser, 0, b"123456"); 250 | } 251 | 252 | #[test] 253 | fn skip() { 254 | let mut parser = Parser::new(b"123456"); 255 | check(&parser, 0, b"123456"); 256 | parser.skip(2).unwrap(); 257 | check(&parser, 2, b"3456"); 258 | assert_eq!(parser.skip(6), Err(ParseError::UnexpectedEnd)); 259 | check(&parser, 2, b"3456"); 260 | } 261 | 262 | #[test] 263 | fn parse_u8() { 264 | let mut parser = Parser::new(b"123"); 265 | check(&parser, 0, b"123"); 266 | assert_eq!(parser.parse_u8().unwrap(), b'1'); 267 | check(&parser, 1, b"23"); 268 | } 269 | 270 | #[test] 271 | fn parse_u16() { 272 | let mut parser = Parser::new(b"\x12\x3456"); 273 | check(&parser, 0, b"\x12\x3456"); 274 | assert_eq!(parser.parse_u16().unwrap(), 0x1234); 275 | check(&parser, 2, b"56"); 276 | } 277 | 278 | #[test] 279 | fn parse_u32() { 280 | let mut parser = Parser::new(b"\x12\x34\x56\x7890"); 281 | check(&parser, 0, b"\x12\x34\x56\x7890"); 282 | assert_eq!(parser.parse_u32().unwrap(), 0x12345678); 283 | check(&parser, 4, b"90"); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/bits/question.rs: -------------------------------------------------------------------------------- 1 | //! A single question of a DNS message. 2 | //! 3 | //! This module defines the type `Question` which represents an entry in 4 | //! the question section of a DNS message. 5 | 6 | use std::fmt; 7 | use ::iana::{Class, Rtype}; 8 | use super::{Composer, ComposeResult, DName, ParsedDName, Parser, ParseResult}; 9 | 10 | 11 | //------------ Question ----------------------------------------------------- 12 | 13 | /// A question in a DNS message. 14 | /// 15 | /// In DNS, a query is determined by three elements: a domain name, a record 16 | /// type, and a class, collectively called a question. This type represents 17 | /// such a question. 18 | /// 19 | /// Questions are generic over the domain name type. For a question with a 20 | /// [`ParsedDName`], parsing is implemented. Composing, meanwhile, is 21 | /// available with all domain name types. 22 | /// 23 | /// In order to allow questions on the fly, in particular when creating 24 | /// messages via [`MessageBuilder`], the `From` trait is implemented for 25 | /// tuples of all three elements of a question as well as for only name 26 | /// and record type assuming `Class::In` which is likely what you want, 27 | /// anyway. 28 | /// 29 | /// [`ParsedDName`]: ../name/struct.ParsedDName.html 30 | /// [`MessageBuilder`]: ../message_builder/struct.MessageBuilder.html 31 | #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 32 | pub struct Question { 33 | /// The domain name of the question. 34 | qname: N, 35 | 36 | /// The record type of the question. 37 | qtype: Rtype, 38 | 39 | /// The class of the quesiton. 40 | qclass: Class, 41 | } 42 | 43 | 44 | /// # Creation and Conversion 45 | /// 46 | impl Question { 47 | /// Creates a new question from its constituent elements. 48 | pub fn new(qname: N, qtype: Rtype, qclass: Class) -> Self { 49 | Question { qname: qname, qtype: qtype, qclass: qclass } 50 | } 51 | } 52 | 53 | 54 | /// # Element Access 55 | /// 56 | impl Question { 57 | /// Returns the requested domain name. 58 | pub fn qname(&self) -> &N { 59 | &self.qname 60 | } 61 | 62 | /// Returns the requested record type. 63 | pub fn qtype(&self) -> Rtype { 64 | self.qtype 65 | } 66 | 67 | /// Returns the requested class. 68 | pub fn qclass(&self) -> Class { 69 | self.qclass 70 | } 71 | } 72 | 73 | 74 | /// # Parsing 75 | /// 76 | impl<'a> Question> { 77 | /// Parses a question from the beginning of a parser. 78 | pub fn parse(parser: &mut Parser<'a>) -> ParseResult { 79 | Ok(Question::new(try!(ParsedDName::parse(parser)), 80 | try!(Rtype::parse(parser)), 81 | try!(Class::parse(parser)))) 82 | } 83 | } 84 | 85 | 86 | /// # Composing 87 | /// 88 | impl Question { 89 | /// Appends the question to a composition. 90 | pub fn compose>(&self, mut composer: C) 91 | -> ComposeResult<()> { 92 | try!(self.qname.compose(composer.as_mut())); 93 | try!(self.qtype.compose(composer.as_mut())); 94 | self.qclass.compose(composer.as_mut()) 95 | } 96 | } 97 | 98 | 99 | //--- From 100 | 101 | impl From<(N, Rtype, Class)> for Question { 102 | fn from(src: (N, Rtype, Class)) -> Self { 103 | Self::new(src.0, src.1, src.2) 104 | } 105 | } 106 | 107 | impl From<(N, Rtype)> for Question { 108 | fn from(src: (N, Rtype)) -> Self { 109 | Self::new(src.0, src.1, Class::In) 110 | } 111 | } 112 | 113 | 114 | //--- Display 115 | 116 | impl fmt::Display for Question { 117 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 118 | write!(f, "{} {} {}", self.qname, self.qtype, self.qclass) 119 | } 120 | } 121 | 122 | impl fmt::Octal for Question { 123 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 124 | write!(f, "{:o} {} {}", self.qname, self.qtype, self.qclass) 125 | } 126 | } 127 | 128 | impl fmt::LowerHex for Question { 129 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 130 | write!(f, "{:x} {} {}", self.qname, self.qtype, self.qclass) 131 | } 132 | } 133 | 134 | impl fmt::UpperHex for Question { 135 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 136 | write!(f, "{:X} {} {}", self.qname, self.qtype, self.qclass) 137 | } 138 | } 139 | 140 | impl fmt::Binary for Question { 141 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 142 | write!(f, "{:b} {} {}", self.qname, self.qtype, self.qclass) 143 | } 144 | } 145 | 146 | -------------------------------------------------------------------------------- /src/bits/rdata.rs: -------------------------------------------------------------------------------- 1 | //! Basic resource data handling. 2 | //! 3 | //! DNS resource records consist of some common data defining the domain 4 | //! name they pertain to, their type and class, and finally record data 5 | //! the format of which depends on the specific record type. As there are 6 | //! currently more than eighty record types, having a giant enum for record 7 | //! data seemed like a bad idea. Instead, resource records are generic over 8 | //! two traits defined by this module. All concrete types implement 9 | //! [`RecordData`]. Types that can be parsed out of messages also implement 10 | //! [`ParsedRecordData`]. This distinction is only relevant for types that 11 | //! contain and are generic over domain names: for these, parsing is only 12 | //! available if the names use [`ParsedDName`]. 13 | //! 14 | //! All concrete types shipped with this crate are implemented in the 15 | //! [`domain::rdata`] module. 16 | //! 17 | //! In order to walk over all resource records in a message or work with 18 | //! unknown record types, this module also defines the [`GenericRecordData`] 19 | //! type that can deal with all record types but provides only a limited 20 | //! functionality. 21 | //! 22 | //! [`RecordData`]: trait.RecordData.html 23 | //! [`ParsedRecordData`]: trait.ParsedRecordData.html 24 | //! [`domain::rdata`]: ../../rdata/index.html 25 | //! [`GenericRecordData`]: struct.GenericRecordData.html 26 | 27 | use std::fmt; 28 | use ::iana::Rtype; 29 | use ::rdata::fmt_rdata; 30 | use super::{Composer, ComposeResult, Parser, ParseResult}; 31 | 32 | 33 | //----------- RecordData ----------------------------------------------------- 34 | 35 | /// A trait for types representing record data. 36 | pub trait RecordData: Sized { 37 | /// Returns the record type for this record data instance. 38 | /// 39 | /// This is a method rather than an associated function to allow one 40 | /// type to be used for several real record types. 41 | fn rtype(&self) -> Rtype; 42 | 43 | /// Appends the record data to the end of a composer. 44 | fn compose>(&self, target: C) -> ComposeResult<()>; 45 | } 46 | 47 | 48 | //------------ ParsedRecordData ---------------------------------------------- 49 | 50 | /// A trait for types that allow parsing record data from a message. 51 | pub trait ParsedRecordData<'a>: RecordData { 52 | /// Parses the record data out of a parser. 53 | /// 54 | /// The `parser` handed into the function will be limited to the length 55 | /// of the record data, so can read until the end of the parser. 56 | fn parse(rtype: Rtype, parser: &mut Parser<'a>) 57 | -> ParseResult>; 58 | } 59 | 60 | 61 | //------------ GenericRecordData -------------------------------------------- 62 | 63 | /// A type for parsing any type of record data. 64 | /// 65 | /// This type accepts any record type and stores a reference to the plain 66 | /// binary record data in the message. This way, it can later be converted 67 | /// into concrete record data if necessary via the [`reparse()`] method. 68 | /// 69 | /// Because the data referenced by a value may contain compressed domain 70 | /// names, transitively building a new message from this data may lead to 71 | /// corrupt messages. To avoid this sort of thing, 72 | /// [RFC 3597], ‘Handling of Unknown DNS Resource Record (RR) Types,’ 73 | /// restricted compressed domain names to record types defined in [RFC 1035]. 74 | /// Accordingly, this types [`RecordData::compose()`] implementation treats 75 | /// these types specially and ensures that their names are handles correctly. 76 | /// This may still lead to corrupt messages, however, if the generic record 77 | /// data is obtained from a source not complying with RFC 3597. In general, 78 | /// be wary when re-composing parsed messages unseen. 79 | /// 80 | /// [`RecordData::compose()`]: trait.RecordData.html#tymethod.compose 81 | /// [RFC 1035]: https://tools.ietf.org/html/rfc1035 82 | /// [RFC 3597]: https://tools.ietf.org/html/rfc3597 83 | #[derive(Clone, Debug)] 84 | pub struct GenericRecordData<'a> { 85 | /// The record type of this data. 86 | rtype: Rtype, 87 | 88 | /// A parser for the record’s data. 89 | /// 90 | /// The parser will be positioned at the beginning of the record data and 91 | /// will be limited to the length of the record data. 92 | parser: Parser<'a>, 93 | } 94 | 95 | impl<'a> GenericRecordData<'a> { 96 | /// Tries to re-parse the data for the given record data type. 97 | /// 98 | /// # Panics 99 | /// 100 | /// This method panics if the specified record data type does not 101 | /// actually feel like parsing data of the value’s record type. 102 | fn reparse>(&self) -> ParseResult { 103 | D::parse(self.rtype, &mut self.parser.clone()).map(Option::unwrap) 104 | } 105 | } 106 | 107 | impl<'a> RecordData for GenericRecordData<'a> { 108 | fn rtype(&self) -> Rtype { 109 | self.rtype 110 | } 111 | 112 | fn compose>(&self, mut target: C) 113 | -> ComposeResult<()> { 114 | use ::rdata::rfc1035::parsed::*; 115 | 116 | match self.rtype { 117 | // Special treatment for any type from RFC 1035 that contains 118 | // domain names. 119 | Rtype::Cname => try!(self.reparse::()).compose(target), 120 | Rtype::Mb => try!(self.reparse::()).compose(target), 121 | Rtype::Md => try!(self.reparse::()).compose(target), 122 | Rtype::Mf => try!(self.reparse::()).compose(target), 123 | Rtype::Mg => try!(self.reparse::()).compose(target), 124 | Rtype::Minfo => try!(self.reparse::()).compose(target), 125 | Rtype::Mr => try!(self.reparse::()).compose(target), 126 | Rtype::Mx => try!(self.reparse::()).compose(target), 127 | Rtype::Ns => try!(self.reparse::()).compose(target), 128 | Rtype::Ptr => try!(self.reparse::()).compose(target), 129 | Rtype::Soa => try!(self.reparse::()).compose(target), 130 | 131 | // Anything else can go verbatim. 132 | _ => { 133 | let len = self.parser.remaining(); 134 | let bytes = try!(self.parser.clone().parse_bytes(len)); 135 | target.as_mut().compose_bytes(bytes) 136 | } 137 | } 138 | } 139 | } 140 | 141 | impl<'a> ParsedRecordData<'a> for GenericRecordData<'a> { 142 | fn parse(rtype: Rtype, parser: &mut Parser<'a>) 143 | -> ParseResult> { 144 | let my_parser = parser.clone(); 145 | let len = parser.remaining(); 146 | try!(parser.skip(len)); 147 | Ok(Some(GenericRecordData { 148 | rtype: rtype, 149 | parser: my_parser 150 | })) 151 | } 152 | } 153 | 154 | impl<'a> fmt::Display for GenericRecordData<'a> { 155 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 156 | fmt_rdata(self.rtype, &mut self.parser.clone(), f) 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /src/iana/class.rs: -------------------------------------------------------------------------------- 1 | //! DNS CLASSes. 2 | 3 | use ::master::{ScanResult, Scanner, SyntaxError}; 4 | use ::bits::{Composer, ComposeResult, Parser, ParseResult}; 5 | 6 | int_enum!{ 7 | /// DNS CLASSes. 8 | /// 9 | /// The domain name space is partitioned into separate classes for different 10 | /// network types. That is, each class has its own separate record tree 11 | /// starting at the root. However, in practice, only the IN class is really 12 | /// relevant. 13 | /// 14 | /// In addition, there are query classes or QCLASSes that are used in 15 | /// questions or UPDATE queries, namely NONE and ANY (or *). 16 | /// 17 | /// Classes are represented by a 16 bit value. The enum wraps these values. 18 | /// 19 | /// See [RFC 1034] for the introduction of classes, section 3.2 of 20 | /// [RFC 6895] for a discussion of the current state of afairs, and 21 | /// the [DNS CLASSes IANA registry] for an overview of assigned values. 22 | /// 23 | /// [RFC 1034]: https://tools.ietf.org/html/rfc1034 24 | /// [RFC 6895]: https://tools.ietf.org/html/rfc6895 25 | /// [DNS CLASSes IANA registry]: http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2 26 | => 27 | Class, u16; 28 | 29 | /// Internet (IN). 30 | /// 31 | /// This class is defined in RFC 1035 and really the only one relevant 32 | /// at all. 33 | (In => 1, b"IN") 34 | 35 | /// Chaosnet (CH). 36 | /// 37 | /// A network protocol developed at MIT in the 1970s. Reused by BIND for 38 | /// built-in server information zones.", 39 | (Ch => 3, b"CH") 40 | 41 | /// Hesiod (HS). 42 | /// 43 | /// A system information protocol part of MIT's Project Athena.", 44 | (Hs => 4, b"HS") 45 | 46 | /// Query class None. 47 | /// 48 | /// Defined in RFC 2136, this class is used in UPDATE queries to 49 | /// require that an RRset does not exist prior to the update.", 50 | (None => 0xFE, b"NONE") 51 | 52 | /// Query class * (ANY). 53 | /// 54 | /// This class can be used in a query to indicate that records for the 55 | /// given name from any class are requested.", 56 | (Any => 0xFF, b"*") 57 | } 58 | 59 | int_enum_str_with_prefix!(Class, "CLASS", b"CLASS", u16, "unknown class"); 60 | 61 | impl Class { 62 | pub fn parse(parser: &mut Parser) -> ParseResult { 63 | parser.parse_u16().map(Class::from) 64 | } 65 | 66 | pub fn compose>(&self, mut composer: C) 67 | -> ComposeResult<()> { 68 | composer.as_mut().compose_u16(self.into()) 69 | } 70 | 71 | pub fn scan(scanner: &mut S) -> ScanResult { 72 | scanner.scan_word(|slice| { 73 | Class::from_bytes(slice) 74 | .ok_or_else(|| SyntaxError::UnknownClass(slice.into())) 75 | }) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/iana/mod.rs: -------------------------------------------------------------------------------- 1 | //! IANA Definitions for DNS. 2 | //! 3 | //! This module contains enums for parameters defined in IANA registries 4 | //! that are relevant for this crate. 5 | //! 6 | //! All types defined hereunder follow the same basic structure. They are 7 | //! all enums with all well-defined values as variants. In addition they 8 | //! have an `Int` variant that contains a raw integer value. Since we cannot 9 | //! restrict that integer to only the undefined values, we generally allow 10 | //! the full set of possible values. We treat this correctly, meaning that 11 | //! the well-defined variant and the `Int` variant with the same integer 12 | //! value compare to equal. 13 | //! 14 | //! There are two methods `from_int()` and `to_int()` to convert from and 15 | //! to raw integer values as well as implementations of the `From` trait 16 | //! for these. `FromStr` and `Display` are implemented to convert from 17 | //! the string codes to the values and back. All of these are essentially 18 | //! giant matches which may or may not be the smartest way to do this. 19 | //! 20 | //! Types also implement `parse()` and `scan()` functions for creation from 21 | //! wire format and master format, respectively, as well as a `compose()` 22 | //! method for composing into wire format data. 23 | //! 24 | //! While each parameter type has a module of its own, they are all 25 | //! re-exported here. This is mostly so we can have associated types like 26 | //! `FromStrError` without having to resort to devilishly long names. 27 | 28 | pub use self::class::Class; 29 | pub use self::opcode::Opcode; 30 | pub use self::opt::OptionCode; 31 | pub use self::rcode::{Rcode, OptRcode, TsigRcode}; 32 | pub use self::rtype::Rtype; 33 | pub use self::secalg::SecAlg; 34 | 35 | #[macro_use] mod macros; 36 | 37 | pub mod class; 38 | pub mod opcode; 39 | pub mod opt; 40 | pub mod rcode; 41 | pub mod rtype; 42 | pub mod secalg; 43 | 44 | -------------------------------------------------------------------------------- /src/iana/opcode.rs: -------------------------------------------------------------------------------- 1 | //! DNS OpCodes 2 | 3 | use std::cmp; 4 | use std::convert; 5 | use std::fmt; 6 | use std::hash; 7 | 8 | 9 | /// DNS OpCodes. 10 | /// 11 | /// The opcode specifies the kind of query to be performed. 12 | /// 13 | /// The opcode is initially defined in RFC 1035. All currently assigned 14 | /// values can be found at 15 | /// http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-5 16 | #[derive(Clone, Copy, Debug)] 17 | pub enum Opcode { 18 | /// A standard query. 19 | /// 20 | /// This query requests all records matching the name, class, and record 21 | /// type given in the query’s question section. 22 | /// 23 | /// This value is defined in RFC 1035. 24 | Query, 25 | 26 | /// An inverse query (IQUERY) (obsolete). 27 | /// 28 | /// The idea behind inverse queries was to provide a single answer and 29 | /// ask the DNS for all the questions that would lead to this answer. 30 | /// This kind of query has always been optional, was never widely 31 | /// supported, and has therefore been declared obsolete. 32 | /// 33 | /// This value was defined in RFC 1035 and obsoleted by RFC 3425. 34 | IQuery, 35 | 36 | /// A server status request. 37 | /// 38 | /// This value is defined in RFC 1035. The status request itself was 39 | /// defined as experimental and ‘to be defined’ in RFC 1034 and seems 40 | /// to never have been mentioned ever again. 41 | Status, 42 | 43 | /// A NOTIFY query. 44 | /// 45 | /// NOTIFY queries allow master servers to inform slave servers when a 46 | /// zone has changed. 47 | /// 48 | /// This value and the NOTIFY query are defined in RFC 1996. 49 | Notify, 50 | 51 | /// An UPDATE query. 52 | /// 53 | /// The UPDATE query can be used to alter zone content managed by a 54 | /// master server. 55 | /// 56 | /// This value and the UPDATE query are defined in RFC 2136. 57 | Update, 58 | 59 | /// A raw integer opcode value. 60 | /// 61 | /// When converting to an `u8`, only the lower four bits are used. 62 | Int(u8) 63 | } 64 | 65 | impl Opcode { 66 | /// Creates an Opcode value from an integer value. 67 | /// 68 | /// Only considers the lower four bits of `value`. 69 | pub fn from_int(value: u8) -> Opcode { 70 | use self::Opcode::*; 71 | 72 | match value & 0x0F { 73 | 0 => Query, 74 | 1 => IQuery, 75 | 2 => Status, 76 | 4 => Notify, 77 | 5 => Update, 78 | value => Int(value) 79 | } 80 | } 81 | 82 | /// Returns the integer value for this opcode. 83 | pub fn to_int(self) -> u8 { 84 | use self::Opcode::*; 85 | 86 | match self { 87 | Query => 0, 88 | IQuery => 1, 89 | Status => 2, 90 | Notify => 4, 91 | Update => 5, 92 | Int(value) => value & 0x0F 93 | } 94 | } 95 | } 96 | 97 | 98 | //--- From 99 | 100 | impl convert::From for Opcode { 101 | fn from(value: u8) -> Opcode { Opcode::from_int(value) } 102 | } 103 | 104 | impl convert::From for u8 { 105 | fn from(value: Opcode) -> u8 { Opcode::to_int(value) } 106 | } 107 | 108 | 109 | //--- Display 110 | 111 | impl fmt::Display for Opcode { 112 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 113 | use self::Opcode::*; 114 | 115 | match *self { 116 | Query => "QUERY".fmt(f), 117 | IQuery => "IQUERY".fmt(f), 118 | Status => "STATUS".fmt(f), 119 | Notify => "NOTIFY".fmt(f), 120 | Update => "UPDATE".fmt(f), 121 | Int(value) => { 122 | match Opcode::from_int(value) { 123 | Int(value) => value.fmt(f), 124 | value => value.fmt(f) 125 | } 126 | } 127 | } 128 | } 129 | } 130 | 131 | 132 | //--- PartialEq and Eq 133 | 134 | impl cmp::PartialEq for Opcode { 135 | fn eq(&self, other: &Opcode) -> bool { 136 | self.to_int() == other.to_int() 137 | } 138 | } 139 | 140 | impl cmp::PartialEq for Opcode { 141 | fn eq(&self, other: &u8) -> bool { 142 | self.to_int() == *other 143 | } 144 | } 145 | 146 | impl cmp::PartialEq for u8 { 147 | fn eq(&self, other: &Opcode) -> bool { 148 | *self == other.to_int() 149 | } 150 | } 151 | 152 | impl cmp::Eq for Opcode { } 153 | 154 | 155 | //--- PartialCmp and Cmp 156 | 157 | impl cmp::PartialOrd for Opcode { 158 | fn partial_cmp(&self, other: &Self) -> Option { 159 | self.to_int().partial_cmp(&other.to_int()) 160 | } 161 | } 162 | 163 | impl cmp::PartialOrd for Opcode { 164 | fn partial_cmp(&self, other: &u8) -> Option { 165 | self.to_int().partial_cmp(other) 166 | } 167 | } 168 | 169 | impl cmp::PartialOrd for u8 { 170 | fn partial_cmp(&self, other: &Opcode) -> Option { 171 | self.partial_cmp(&other.to_int()) 172 | } 173 | } 174 | 175 | impl cmp::Ord for Opcode { 176 | fn cmp(&self, other: &Self) -> cmp::Ordering { 177 | self.to_int().cmp(&other.to_int()) 178 | } 179 | } 180 | 181 | 182 | //--- Hash 183 | 184 | impl hash::Hash for Opcode { 185 | fn hash(&self, state: &mut H) { 186 | self.to_int().hash(state) 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/iana/opt.rs: -------------------------------------------------------------------------------- 1 | //! DNS EDNS0 Option Codes (OPT) 2 | 3 | use std::cmp; 4 | use std::fmt; 5 | use std::hash; 6 | 7 | 8 | //------------ OptionCode --------------------------------------------------- 9 | 10 | /// DNS EDNS0 Option Codes (OPT) 11 | /// 12 | /// The record data of OPT records is a sequence of options. The type of each 13 | /// of these options is given through an option code, a 16 bit value. 14 | /// 15 | /// The currently assigned option codes can be found in 16 | /// http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11 17 | #[derive(Clone, Copy, Debug)] 18 | pub enum OptionCode { 19 | Llq, 20 | Ul, 21 | Nsid, 22 | Dau, 23 | Dhu, 24 | N3u, 25 | EdnsClientSubnet, 26 | EdnsExpire, 27 | Cookie, 28 | EdnsTcpKeepalive, 29 | Padding, 30 | Chain, 31 | EdnsKeyTag, 32 | 33 | /// A raw class value given through its integer. 34 | Int(u16), 35 | } 36 | 37 | impl OptionCode { 38 | /// Returns the option code for the given raw integer value. 39 | pub fn from_int(value: u16) -> Self { 40 | use self::OptionCode::*; 41 | 42 | match value { 43 | 1 => Llq, 44 | 2 => Ul, 45 | 3 => Nsid, 46 | 5 => Dau, 47 | 6 => Dhu, 48 | 7 => N3u, 49 | 8 => EdnsClientSubnet, 50 | 9 => EdnsExpire, 51 | 10 => Cookie, 52 | 11 => EdnsTcpKeepalive, 53 | 12 => Padding, 54 | 13 => Chain, 55 | 14 => EdnsKeyTag, 56 | _ => Int(value) 57 | } 58 | } 59 | 60 | /// Returns the raw integer value for this option code. 61 | pub fn to_int(self) -> u16 { 62 | use self::OptionCode::*; 63 | 64 | match self { 65 | Llq => 1, 66 | Ul => 2, 67 | Nsid => 3, 68 | Dau => 5, 69 | Dhu => 6, 70 | N3u => 7, 71 | EdnsClientSubnet => 8, 72 | EdnsExpire => 9, 73 | Cookie => 10, 74 | EdnsTcpKeepalive => 11, 75 | Padding => 12, 76 | Chain => 13, 77 | EdnsKeyTag => 14, 78 | Int(v) => v 79 | } 80 | } 81 | } 82 | 83 | 84 | //--- From 85 | 86 | impl From for OptionCode { 87 | fn from(value: u16) -> Self { 88 | OptionCode::from_int(value) 89 | } 90 | } 91 | 92 | impl From for u16 { 93 | fn from(value: OptionCode) -> Self { 94 | value.to_int() 95 | } 96 | } 97 | 98 | 99 | //--- Display 100 | 101 | impl fmt::Display for OptionCode { 102 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 103 | use self::OptionCode::*; 104 | 105 | match *self { 106 | Llq => "LLQ".fmt(f), 107 | Ul => "UL".fmt(f), 108 | Nsid => "NSID".fmt(f), 109 | Dau => "DAU".fmt(f), 110 | Dhu => "DHU".fmt(f), 111 | N3u => "N3U".fmt(f), 112 | EdnsClientSubnet => "edns-client-subnet".fmt(f), 113 | EdnsExpire => "EDNS EXPIRE".fmt(f), 114 | Cookie => "COOKIE".fmt(f), 115 | EdnsTcpKeepalive => "edns-tcp-keepalive".fmt(f), 116 | Padding => "Padding".fmt(f), 117 | Chain => "CHAIN".fmt(f), 118 | EdnsKeyTag => "edns-key-tag".fmt(f), 119 | Int(value) => { 120 | match OptionCode::from_int(value) { 121 | Int(value) => value.fmt(f), 122 | value => value.fmt(f), 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | 130 | //--- PartialEq and Eq 131 | 132 | impl PartialEq for OptionCode { 133 | fn eq(&self, other: &Self) -> bool { 134 | self.to_int() == other.to_int() 135 | } 136 | } 137 | 138 | impl PartialEq for OptionCode { 139 | fn eq(&self, other: &u16) -> bool { 140 | self.to_int() == *other 141 | } 142 | } 143 | 144 | impl PartialEq for u16 { 145 | fn eq(&self, other: &OptionCode) -> bool { 146 | *self == other.to_int() 147 | } 148 | } 149 | 150 | impl Eq for OptionCode { } 151 | 152 | 153 | //--- PartialOrd and Ord 154 | 155 | impl PartialOrd for OptionCode { 156 | fn partial_cmp(&self, other: &Self) -> Option { 157 | self.to_int().partial_cmp(&other.to_int()) 158 | } 159 | } 160 | 161 | impl PartialOrd for OptionCode { 162 | fn partial_cmp(&self, other: &u16) -> Option { 163 | self.to_int().partial_cmp(other) 164 | } 165 | } 166 | 167 | impl PartialOrd for u16 { 168 | fn partial_cmp(&self, other: &OptionCode) -> Option { 169 | self.partial_cmp(&other.to_int()) 170 | } 171 | } 172 | 173 | impl Ord for OptionCode { 174 | fn cmp(&self, other: &Self) -> cmp::Ordering { 175 | self.to_int().cmp(&other.to_int()) 176 | } 177 | } 178 | 179 | 180 | //--- Hash 181 | 182 | impl hash::Hash for OptionCode { 183 | fn hash(&self, state: &mut H) { 184 | self.to_int().hash(state) 185 | } 186 | } 187 | 188 | -------------------------------------------------------------------------------- /src/iana/secalg.rs: -------------------------------------------------------------------------------- 1 | //! DNSSEC Algorithm Numbers 2 | 3 | use std::cmp; 4 | use std::fmt; 5 | use std::hash; 6 | use std::str; 7 | 8 | 9 | //------------ SecAlg ------------------------------------------------------- 10 | 11 | /// See http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#dns-sec-alg-numbers-1 12 | #[derive(Clone, Copy, Debug)] 13 | pub enum SecAlg { 14 | /// RSA/MD5 15 | /// 16 | /// This algorithm was described in RFC 2537 and since has been 17 | /// deprecated due to weaknesses of the MD5 hash algorithm by RFC 3110 18 | /// which suggests to use RSA/SHA1 instead. 19 | /// 20 | /// This algorithm may not be used for zone signing but may be used 21 | /// for transaction security. 22 | RsaMd5, 23 | 24 | /// Diffie-Hellman 25 | /// 26 | /// This algorithm is described in RFC 2539 for storing Diffie-Hellman 27 | /// (DH) keys in DNS resource records. It can not be used for zone 28 | /// signing but only for transaction security. 29 | Dh, 30 | 31 | /// DSA/SHA1 32 | /// 33 | /// This algorithm is described in RFC 2536. It may be used both for 34 | /// zone signing and transaction security. 35 | Dsa, 36 | 37 | /// RSA/SHA-1 38 | /// 39 | /// This algorithm is described in RFC 3110. It may be used both for 40 | /// zone signing and transaction security. It is mandatory for DNSSEC 41 | /// implementations. 42 | RsaSha1, 43 | 44 | /// DSA-NSEC3-SHA1 45 | /// 46 | /// This value is an alias for `Dsa` for use within NSEC3 records. 47 | DsaNsec3Sha1, 48 | 49 | /// RSASHA1-NSEC3-SHA1 50 | /// 51 | /// This value is an alias for `RsaSha1` for use within NSEC3 records. 52 | RsaSha1Nsec3Sha1, 53 | 54 | /// RSA/SHA-256 55 | /// 56 | /// This algorithm is described in RFC 5702. It may be used for zone 57 | /// signing only. 58 | RsaSha256, 59 | 60 | /// RSA/SHA-512 61 | /// 62 | /// This algorithm is described in RFC 5702. It may be used for zone 63 | /// signing only. 64 | RsaSha512, 65 | 66 | /// GOST R 34.10-2001 67 | /// 68 | /// This algorithm is described in RFC 5933. It may be used for zone 69 | /// signing only. 70 | EccGost, 71 | 72 | /// ECDSA Curve P-256 with SHA-256 73 | /// 74 | /// This algorithm is described in RFC 6605. It may be used for zone 75 | /// signing only. 76 | EcdsaP256Sha256, 77 | 78 | /// ECDSA Curve P-384 with SHA-384 79 | /// 80 | /// This algorithm is described in RFC 6605. It may be used for zone 81 | /// signing only. 82 | EcdsaP384Sha384, 83 | 84 | /// Reserved for Indirect Keys 85 | /// 86 | /// This value is reserved by RFC 4034. 87 | Indirect, 88 | 89 | /// A private algorithm identified by a domain name. 90 | /// 91 | /// This value is defined in RFC 4034. 92 | PrivateDns, 93 | 94 | /// A private algorithm identified by a ISO OID. 95 | /// 96 | /// This value is defined in RFC 4034. 97 | PrivateOid, 98 | 99 | /// A raw algorithm value given through its integer value. 100 | Int(u8) 101 | } 102 | 103 | impl SecAlg { 104 | /// Returns the algorithm value for the given integer value. 105 | pub fn from_int(value: u8) -> SecAlg { 106 | use self::SecAlg::*; 107 | 108 | match value { 109 | 1 => RsaMd5, 110 | 2 => Dh, 111 | 3 => Dsa, 112 | 5 => RsaSha1, 113 | 6 => DsaNsec3Sha1, 114 | 7 => RsaSha1Nsec3Sha1, 115 | 8 => RsaSha256, 116 | 10 => RsaSha512, 117 | 12 => EccGost, 118 | 13 => EcdsaP256Sha256, 119 | 14 => EcdsaP384Sha384, 120 | 252 => Indirect, 121 | 253 => PrivateDns, 122 | 254 => PrivateOid, 123 | _ => Int(value) 124 | } 125 | } 126 | 127 | /// Returns the integer value for this algorithm value. 128 | pub fn to_int(self) -> u8 { 129 | use self::SecAlg::*; 130 | 131 | match self { 132 | RsaMd5 => 1, 133 | Dh => 2, 134 | Dsa => 3, 135 | RsaSha1 => 5, 136 | DsaNsec3Sha1 => 6, 137 | RsaSha1Nsec3Sha1 => 7, 138 | RsaSha256 => 8, 139 | RsaSha512 => 10, 140 | EccGost => 12, 141 | EcdsaP256Sha256 => 13, 142 | EcdsaP384Sha384 => 14, 143 | Indirect => 252, 144 | PrivateDns => 253, 145 | PrivateOid => 254, 146 | Int(value) => value 147 | } 148 | } 149 | } 150 | 151 | 152 | //--- From 153 | 154 | impl From for SecAlg { 155 | fn from(value: u8) -> SecAlg { 156 | SecAlg::from_int(value) 157 | } 158 | } 159 | 160 | impl From for u8 { 161 | fn from(value: SecAlg) -> u8 { 162 | value.to_int() 163 | } 164 | } 165 | 166 | 167 | //--- FromStr 168 | 169 | impl str::FromStr for SecAlg { 170 | type Err = FromStrError; 171 | 172 | /// Returns the algorithm value for the given string. 173 | /// 174 | /// Recognized are the mnemonics equivalent to the algorithm number not 175 | /// regarding case as well as decimal integer numbers. 176 | fn from_str(s: &str) -> Result { 177 | use self::SecAlg::*; 178 | 179 | if s.eq_ignore_ascii_case("RSAMD5") { Ok(RsaMd5) } 180 | else if s.eq_ignore_ascii_case("DH") { Ok(Dh) } 181 | else if s.eq_ignore_ascii_case("DSA") { Ok(Dsa) } 182 | else if s.eq_ignore_ascii_case("RSASHA1") { Ok(RsaSha1) } 183 | else if s.eq_ignore_ascii_case("DSA-NSEC3-SHA1") { Ok(DsaNsec3Sha1) } 184 | else if s.eq_ignore_ascii_case("RSASHA1-NSEC3-SHA1") { 185 | Ok(RsaSha1Nsec3Sha1) 186 | } 187 | else if s.eq_ignore_ascii_case("RSASHA256") { Ok(RsaSha256) } 188 | else if s.eq_ignore_ascii_case("RSASHA512") { Ok(RsaSha512) } 189 | else if s.eq_ignore_ascii_case("ECC-GOST") { Ok(EccGost) } 190 | else if s.eq_ignore_ascii_case("ECDSAP256SHA256") { 191 | Ok(EcdsaP256Sha256) 192 | } 193 | else if s.eq_ignore_ascii_case("ECDSAP384SHA384") { 194 | Ok(EcdsaP384Sha384) 195 | } 196 | else if s.eq_ignore_ascii_case("INDIRECT") { Ok(Indirect) } 197 | else if s.eq_ignore_ascii_case("PRIVATEDNS") { Ok(PrivateDns) } 198 | else if s.eq_ignore_ascii_case("PRIVATEOID") { Ok(PrivateOid) } 199 | else { 200 | match u8::from_str(s) { 201 | Ok(value) => Ok(SecAlg::from_int(value)), 202 | Err(..) => Err(FromStrError) 203 | } 204 | } 205 | } 206 | } 207 | 208 | 209 | //--- Display 210 | 211 | impl fmt::Display for SecAlg { 212 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 213 | use self::SecAlg::*; 214 | 215 | match *self { 216 | RsaMd5 => "RSAMD5".fmt(f), 217 | Dh => "DH".fmt(f), 218 | Dsa => "DSA".fmt(f), 219 | RsaSha1 => "RSASHA1".fmt(f), 220 | DsaNsec3Sha1 => "DSA-NSEC3-SHA1".fmt(f), 221 | RsaSha1Nsec3Sha1 => "RSASHA1-NSEC3-SHA1".fmt(f), 222 | RsaSha256 => "RSASHA256".fmt(f), 223 | RsaSha512 => "RSASHA512".fmt(f), 224 | EccGost => "ECC-GOST".fmt(f), 225 | EcdsaP256Sha256 => "ECDSAP256SHA256".fmt(f), 226 | EcdsaP384Sha384 => "ECDSAP384SHA384".fmt(f), 227 | Indirect => "INDIRECT".fmt(f), 228 | PrivateDns => "PRVIATEDNS".fmt(f), 229 | PrivateOid => "PRIVATEOID".fmt(f), 230 | Int(value) => { 231 | match SecAlg::from_int(value) { 232 | Int(value) => value.fmt(f), 233 | value => value.fmt(f) 234 | } 235 | } 236 | } 237 | } 238 | } 239 | 240 | 241 | //--- PartialEq and Eq 242 | 243 | impl PartialEq for SecAlg { 244 | fn eq(&self, other: &SecAlg) -> bool { 245 | self.to_int() == other.to_int() 246 | } 247 | } 248 | 249 | impl PartialEq for SecAlg { 250 | fn eq(&self, other: &u8) -> bool { 251 | self.to_int() == *other 252 | } 253 | } 254 | 255 | impl PartialEq for u8 { 256 | fn eq(&self, other: &SecAlg) -> bool { 257 | *self == other.to_int() 258 | } 259 | } 260 | 261 | impl Eq for SecAlg { } 262 | 263 | 264 | //--- PartialOrd and Ord 265 | 266 | impl PartialOrd for SecAlg { 267 | fn partial_cmp(&self, other: &SecAlg) -> Option { 268 | self.to_int().partial_cmp(&other.to_int()) 269 | } 270 | } 271 | 272 | impl PartialOrd for SecAlg { 273 | fn partial_cmp(&self, other: &u8) -> Option { 274 | self.to_int().partial_cmp(other) 275 | } 276 | } 277 | 278 | impl PartialOrd for u8 { 279 | fn partial_cmp(&self, other: &SecAlg) -> Option { 280 | self.partial_cmp(&other.to_int()) 281 | } 282 | } 283 | 284 | impl Ord for SecAlg { 285 | fn cmp(&self, other: &SecAlg) -> cmp::Ordering { 286 | self.to_int().cmp(&other.to_int()) 287 | } 288 | } 289 | 290 | 291 | //--- Hash 292 | 293 | impl hash::Hash for SecAlg { 294 | fn hash(&self, state: &mut H) { 295 | self.to_int().hash(state) 296 | } 297 | } 298 | 299 | 300 | from_str_error!("unknown algorithm"); 301 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A DNS library for Rust. 2 | //! 3 | //! This crate provides a wide range of modules related to the Domain Name 4 | //! System. Currently, these are: 5 | //! 6 | //! * fundamental types, traits, and implementations for dealing with DNS 7 | //! data through the modules [bits] and [iana], 8 | //! * parsing of master file data (aka zonefiles) in [master], 9 | //! * data and master file access for various resource record types in 10 | //! [rdata], 11 | //! * an asynchronous stub resolver implementation for querying the DNS 12 | //! in [resolv]. 13 | //! 14 | //! [bits]: bits/index.html 15 | //! [iana]: iana/index.html 16 | //! [master]: master/index.html 17 | //! [rdata]: rdata/index.html 18 | //! [resolv]: resolv/index.html 19 | #![allow(unknown_lints)] // hide clippy-related #allows on stable. 20 | 21 | extern crate byteorder; 22 | #[macro_use] extern crate futures; 23 | extern crate rand; 24 | #[macro_use] extern crate tokio_core; 25 | 26 | pub mod bits; 27 | pub mod iana; 28 | pub mod master; 29 | pub mod rdata; 30 | pub mod utils; 31 | pub mod resolv; 32 | -------------------------------------------------------------------------------- /src/master/entry.rs: -------------------------------------------------------------------------------- 1 | /// A master file entry. 2 | 3 | use std::rc::Rc; 4 | use ::bits::DNameBuf; 5 | use ::iana::Class; 6 | use ::master::{Pos, ScanResult, Scanner, SyntaxError}; 7 | use ::master::record::{MasterRecord, map_origin}; 8 | 9 | 10 | //------------ Entry --------------------------------------------------------- 11 | 12 | /// A master file entry. 13 | /// 14 | /// Master files consist of a sequence of entries. An entry contains data for 15 | /// a resource record or instructions on how to build resource records from 16 | /// the data. 17 | /// 18 | /// This enum has variants for each type of master file entries currently 19 | /// defined. It also knows how to scan itself from a scanner via the 20 | /// `scan()` function. 21 | /// 22 | /// The variants are defined in seciton 5 of [RFC 1035] except where 23 | /// otherwise stated below. 24 | /// 25 | /// [RFC 1035]: https://tools.ietf.org/html/rfc1035 26 | #[derive(Clone, Debug)] 27 | pub enum Entry { 28 | /// An `$ORIGIN` control entry. 29 | /// 30 | /// This entry contains the origin for relative domain names encountered 31 | /// in subsequent entries. 32 | Origin(Rc), 33 | 34 | /// An `$INCLUDE` control entry. 35 | /// 36 | /// This entry instructs the parser to insert the content of the given 37 | /// file at this position. The `path` attribute specifies the path to 38 | /// the file. The interpretation of the contents of this attribute is 39 | /// system dependent. The optional `origin` attribute contains the 40 | /// initial value of the origin of relative domain names when including 41 | /// the file. 42 | Include { path: Vec, origin: Option> }, 43 | 44 | /// A `$TTL` control entry. 45 | /// 46 | /// This entry specifies the value of the TTL field for all subsequent 47 | /// records that do not have it explicitely stated. 48 | /// 49 | /// This entry is defined in section 4 of [RFC 2308]. 50 | /// 51 | /// [RFC 2308]: https://tools.ietf.org/html/rfc2308 52 | Ttl(u32), 53 | 54 | /// Some other control entry. 55 | /// 56 | /// Any other entry starting with a dollar sign is a control entry we 57 | /// do not understand. This variant contains the name of the entry in 58 | /// the `name` attribute and its starting position in `start`. This can 59 | /// be used to produce a meaningful warning or error message. 60 | Control { name: Vec, start: Pos }, 61 | 62 | /// A resource record. 63 | Record(MasterRecord), 64 | 65 | /// A blank entry. 66 | Blank 67 | } 68 | 69 | impl Entry { 70 | /// Scans an entry from a scanner. 71 | /// 72 | /// The four additional arguments contain the state of scanning for 73 | /// entries. 74 | /// 75 | /// The `last_owner` contains the domain name of the last 76 | /// record entry unless this is the first entry. This is used for the 77 | /// `owner` field if a record entry starts with blanks. 78 | /// The `last_class` is the class of the last resource record and is 79 | /// used if a class value is missing from a record entry. 80 | /// The `origin` 81 | /// argument is used for any relative names given in a record entry. 82 | /// The `default_ttl` value is used if a TTL value is missing from a 83 | /// record entry. 84 | /// 85 | /// If successful, the function returns some entry or `None` if it 86 | /// encountered an end of file before an entry even started. 87 | pub fn scan(stream: &mut S, 88 | last_owner: Option>, 89 | last_class: Option, 90 | origin: &Option>, 91 | default_ttl: Option) 92 | -> ScanResult> { 93 | if stream.is_eof() { 94 | Ok(None) 95 | } 96 | else if let Ok(entry) = Entry::scan_control(stream, origin) { 97 | Ok(Some(entry)) 98 | } 99 | else if let Ok(record) = MasterRecord::scan(stream, last_owner, 100 | last_class, origin, 101 | default_ttl) { 102 | Ok(Some(Entry::Record(record))) 103 | } 104 | else { 105 | try!(stream.scan_opt_space()); 106 | try!(stream.scan_newline()); 107 | Ok(Some(Entry::Blank)) 108 | } 109 | } 110 | 111 | /// Tries to scan a control entry. 112 | fn scan_control(stream: &mut S, origin: &Option>) 113 | -> ScanResult { 114 | match try!(ControlType::scan(stream)) { 115 | ControlType::Origin => { 116 | let origin = map_origin(origin); 117 | let name = try!(stream.scan_dname(origin)); 118 | try!(stream.scan_newline()); 119 | Ok(Entry::Origin(Rc::new(name))) 120 | } 121 | ControlType::Include => { 122 | let path = try!(stream.scan_phrase_copy()); 123 | let origin = stream.scan_dname(map_origin(origin)) 124 | .map(Rc::new).ok(); 125 | try!(stream.scan_newline()); 126 | Ok(Entry::Include { path: path, origin: origin }) 127 | } 128 | ControlType::Ttl => { 129 | let ttl = try!(stream.scan_u32()); 130 | try!(stream.scan_newline()); 131 | Ok(Entry::Ttl(ttl)) 132 | } 133 | ControlType::Other(name, pos) => { 134 | try!(stream.skip_entry()); 135 | Ok(Entry::Control { name: name, start: pos }) 136 | } 137 | } 138 | } 139 | } 140 | 141 | 142 | //------------ ControlType --------------------------------------------------- 143 | 144 | /// The type of a control entry. 145 | #[derive(Clone, Debug)] 146 | enum ControlType { 147 | Origin, 148 | Include, 149 | Ttl, 150 | Other(Vec, Pos) 151 | } 152 | 153 | impl ControlType { 154 | fn scan(stream: &mut S) -> ScanResult { 155 | let pos = stream.pos(); 156 | stream.scan_word(|word| { 157 | if word.eq_ignore_ascii_case(b"$ORIGIN") { 158 | Ok(ControlType::Origin) 159 | } 160 | else if word.eq_ignore_ascii_case(b"$INCLUDE") { 161 | Ok(ControlType::Include) 162 | } 163 | else if word.eq_ignore_ascii_case(b"$TTL") { 164 | Ok(ControlType::Ttl) 165 | } 166 | else if let Some(&b'$') = word.get(0) { 167 | Ok(ControlType::Other(word.to_owned(), pos)) 168 | } 169 | else { 170 | Err(SyntaxError::Expected(vec![b'$'])) 171 | } 172 | }) 173 | } 174 | } 175 | 176 | -------------------------------------------------------------------------------- /src/master/error.rs: -------------------------------------------------------------------------------- 1 | /// Errors when dealing with master data. 2 | 3 | use std::io; 4 | use std::net::AddrParseError; 5 | use std::num::ParseIntError; 6 | use std::result; 7 | use std::str::Utf8Error; 8 | use ::bits::name; 9 | 10 | 11 | //------------ SyntaxError --------------------------------------------------- 12 | 13 | /// A syntax error happened while scanning master data. 14 | #[derive(Clone, Debug, PartialEq)] 15 | pub enum SyntaxError { 16 | Expected(Vec), 17 | ExpectedNewline, 18 | ExpectedSpace, 19 | IllegalEscape, 20 | IllegalInteger, 21 | IllegalAddr(AddrParseError), 22 | IllegalName, 23 | IllegalString(Utf8Error), 24 | LongCharStr, 25 | LongLabel, 26 | LongName, 27 | LongGenericData, 28 | NestedParentheses, 29 | NoDefaultTtl, 30 | NoLastClass, 31 | NoLastOwner, 32 | NoOrigin, 33 | RelativeName, 34 | Unexpected(u8), 35 | UnexpectedEof, 36 | UnknownClass(Vec), 37 | UnknownProto(String), 38 | UnknownServ(String), 39 | } 40 | 41 | impl From for SyntaxError { 42 | fn from(_: ParseIntError) -> SyntaxError { 43 | SyntaxError::IllegalInteger 44 | } 45 | } 46 | 47 | impl From for SyntaxError { 48 | fn from(err: AddrParseError) -> SyntaxError { 49 | SyntaxError::IllegalAddr(err) 50 | } 51 | } 52 | 53 | impl From for SyntaxError { 54 | fn from(err: Utf8Error) -> SyntaxError { 55 | SyntaxError::IllegalString(err) 56 | } 57 | } 58 | 59 | #[allow(match_same_arms)] 60 | impl From for SyntaxError { 61 | fn from(err: name::FromStrError) -> SyntaxError { 62 | match err { 63 | name::FromStrError::UnexpectedEnd => SyntaxError::UnexpectedEof, 64 | name::FromStrError::EmptyLabel => SyntaxError::IllegalName, 65 | name::FromStrError::LongLabel => SyntaxError::LongLabel, 66 | name::FromStrError::IllegalEscape => SyntaxError::IllegalEscape, 67 | name::FromStrError::IllegalCharacter => SyntaxError::IllegalName, 68 | name::FromStrError::IllegalBinary => SyntaxError::IllegalName, 69 | name::FromStrError::RelativeName => SyntaxError::RelativeName, 70 | name::FromStrError::LongName => SyntaxError::LongName, 71 | } 72 | } 73 | } 74 | 75 | 76 | //------------ SyntaxError --------------------------------------------------- 77 | 78 | /// A result with a syntax error. 79 | pub type SyntaxResult = result::Result; 80 | 81 | //------------ ScanError ----------------------------------------------------- 82 | 83 | /// An error happened while scanning master data. 84 | #[derive(Debug)] 85 | pub enum ScanError { 86 | Io(io::Error), 87 | Syntax(SyntaxError, Pos) 88 | } 89 | 90 | impl ScanError { 91 | pub fn is_eof(&self) -> bool { 92 | if let ScanError::Syntax(SyntaxError::UnexpectedEof, _) = *self { 93 | true 94 | } 95 | else { false } 96 | } 97 | } 98 | 99 | impl From for ScanError { 100 | fn from(err: io::Error) -> ScanError { 101 | ScanError::Io(err) 102 | } 103 | } 104 | 105 | 106 | //------------ ScanResult ---------------------------------------------------- 107 | 108 | /// A result with a scan error. 109 | pub type ScanResult = result::Result; 110 | 111 | 112 | //------------ Pos ----------------------------------------------------------- 113 | 114 | /// The human-friendly position in a reader. 115 | #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] 116 | pub struct Pos { 117 | line: usize, 118 | col: usize 119 | } 120 | 121 | impl Pos { 122 | pub fn new() -> Pos { 123 | Pos { line: 1, col: 1 } 124 | } 125 | 126 | pub fn line(&self) -> usize { self.line } 127 | pub fn col(&self) -> usize { self.col } 128 | 129 | pub fn update(&mut self, ch: u8) { 130 | match ch { 131 | b'\n' => { self.line += 1; self.col = 1 } 132 | _ => self.col += 1 133 | } 134 | } 135 | 136 | pub fn prev(&self) -> Pos { 137 | Pos { line: self.line, 138 | col: if self.col <= 1 { 1 } else { self.col - 1 } 139 | } 140 | } 141 | } 142 | 143 | impl From<(usize, usize)> for Pos { 144 | fn from(src: (usize, usize)) -> Pos { 145 | Pos { line: src.0, col: src.1 } 146 | } 147 | } 148 | 149 | impl PartialEq<(usize, usize)> for Pos { 150 | fn eq(&self, other: &(usize, usize)) -> bool { 151 | self.line == other.0 && self.col == other.1 152 | } 153 | } 154 | 155 | -------------------------------------------------------------------------------- /src/master/mod.rs: -------------------------------------------------------------------------------- 1 | //! Reading and writing of master files. 2 | 3 | pub use self::error::{Pos, ScanError, ScanResult, SyntaxError, SyntaxResult}; 4 | pub use self::scanner::Scanner; 5 | 6 | pub mod bufscanner; 7 | pub mod entry; 8 | pub mod error; 9 | pub mod reader; 10 | pub mod record; 11 | pub mod scanner; 12 | 13 | -------------------------------------------------------------------------------- /src/master/reader.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | use std::fs::File; 4 | use std::io; 5 | use std::path::Path; 6 | use std::rc::Rc; 7 | use ::bits::name::DNameBuf; 8 | use ::iana::Class; 9 | use ::master::bufscanner::BufScanner; 10 | use ::master::entry::Entry; 11 | use ::master::error::ScanResult; 12 | use ::master::record::MasterRecord; 13 | use ::master::scanner::Scanner; 14 | 15 | 16 | pub struct Reader { 17 | scanner: Option, 18 | origin: Option>, 19 | ttl: Option, 20 | last: Option<(Rc, Class)>, 21 | } 22 | 23 | impl Reader { 24 | pub fn new(scanner: S) -> Self { 25 | Reader { 26 | scanner: Some(scanner), 27 | origin: None, 28 | ttl: None, 29 | last: None 30 | } 31 | } 32 | } 33 | 34 | impl Reader> { 35 | pub fn open>(path: P) -> io::Result { 36 | Ok(Reader::new(try!(BufScanner::open(path)))) 37 | } 38 | } 39 | 40 | impl> Reader>> { 41 | pub fn create(t: T) -> Self { 42 | Reader::new(BufScanner::create(t)) 43 | } 44 | } 45 | 46 | impl Reader { 47 | fn last_owner(&self) -> Option> { 48 | if let Some((ref name, _)) = self.last { 49 | Some(name.clone()) 50 | } 51 | else { 52 | None 53 | } 54 | } 55 | 56 | fn last_class(&self) -> Option { 57 | if let Some((_, class)) = self.last { 58 | Some(class) 59 | } 60 | else { 61 | None 62 | } 63 | } 64 | 65 | fn next_entry(&mut self) -> ScanResult> { 66 | let last_owner = self.last_owner(); 67 | let last_class = self.last_class(); 68 | if let Some(ref mut scanner) = self.scanner { 69 | Entry::scan(scanner, last_owner, last_class, &self.origin, 70 | self.ttl) 71 | } 72 | else { 73 | Ok(None) 74 | } 75 | } 76 | 77 | #[allow(match_same_arms)] 78 | pub fn next_record(&mut self) -> ScanResult> { 79 | loop { 80 | match self.next_entry() { 81 | Ok(Some(Entry::Origin(origin))) => self.origin = Some(origin), 82 | Ok(Some(Entry::Include{path, origin})) => { 83 | return Ok(Some(ReaderItem::Include { path: path, 84 | origin: origin })) 85 | } 86 | Ok(Some(Entry::Ttl(ttl))) => self.ttl = Some(ttl), 87 | Ok(Some(Entry::Control{..})) => { }, 88 | Ok(Some(Entry::Record(record))) => { 89 | self.last = Some((record.owner.clone(), record.class)); 90 | return Ok(Some(ReaderItem::Record(record))) 91 | } 92 | Ok(Some(Entry::Blank)) => { } 93 | Ok(None) => return Ok(None), 94 | Err(err) => { 95 | self.scanner = None; 96 | return Err(err) 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | impl Iterator for Reader { 104 | type Item = ScanResult; 105 | 106 | fn next(&mut self) -> Option> { 107 | match self.next_record() { 108 | Ok(Some(res)) => Some(Ok(res)), 109 | Ok(None) => None, 110 | Err(err) => Some(Err(err)) 111 | } 112 | } 113 | } 114 | 115 | 116 | #[derive(Clone, Debug)] 117 | pub enum ReaderItem { 118 | Record(MasterRecord), 119 | Include { path: Vec, origin: Option> } 120 | } 121 | 122 | impl fmt::Display for ReaderItem { 123 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 124 | match *self { 125 | ReaderItem::Record(ref record) => write!(f, "{}", record), 126 | ReaderItem::Include{ref path, ref origin} => { 127 | try!(write!(f, "$INCLUDE {}", String::from_utf8_lossy(path))); 128 | if let Some(ref origin) = *origin { 129 | try!(write!(f, " {}", origin)); 130 | } 131 | Ok(()) 132 | } 133 | } 134 | } 135 | } 136 | 137 | 138 | //============ Test ========================================================== 139 | 140 | #[cfg(test)] 141 | mod test { 142 | use super::*; 143 | use ::master::error::ScanError; 144 | 145 | #[test] 146 | fn print() { 147 | let reader = Reader::create(&b"$ORIGIN ISI.EDU. 148 | $TTL 86400 149 | @ IN SOA VENERA Action\\.domains ( 150 | 20 ; SERIAL 151 | 7200 ; REFRESH 152 | 600 ; RETRY 153 | 3600000; EXPIRE 154 | 60) ; MINIMUM 155 | 156 | NS A.ISI.EDU. 157 | NS VENERA 158 | NS VAXA 159 | MX 10 VENERA 160 | MX 20 VAXA 161 | 162 | A A 26.3.0.103 163 | 164 | VENERA A 10.1.0.52 165 | A 128.9.0.32 166 | 167 | VAXA A 10.2.0.27 168 | A 128.9.0.33 169 | 170 | 171 | $INCLUDE ISI-MAILBOXES.TXT"[..]); 172 | 173 | for item in reader { 174 | match item { 175 | Ok(item) => println!("{}", item), 176 | Err(ScanError::Syntax(err, pos)) => { 177 | println!("{}:{}: {:?}", pos.line(), pos.col(), err); 178 | } 179 | Err(err) => println!("{:?}", err) 180 | } 181 | } 182 | } 183 | } 184 | 185 | -------------------------------------------------------------------------------- /src/master/record.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | use std::rc::Rc; 4 | use ::bits::{DNameBuf, DNameSlice, RecordData}; 5 | use ::iana::{Class, Rtype}; 6 | use ::rdata::MasterRecordData; 7 | use super::{ScanError, ScanResult, Scanner, SyntaxError}; 8 | 9 | 10 | #[derive(Clone, Debug)] 11 | pub struct MasterRecord { 12 | pub owner: Rc, 13 | pub class: Class, 14 | pub ttl: u32, 15 | pub rdata: MasterRecordData, 16 | } 17 | 18 | impl MasterRecord { 19 | pub fn new(owner: Rc, class: Class, ttl: u32, 20 | rdata: MasterRecordData) -> Self { 21 | MasterRecord { owner: owner, class: class, 22 | ttl: ttl, rdata: rdata } 23 | } 24 | } 25 | 26 | impl MasterRecord { 27 | pub fn scan(stream: &mut S, 28 | last_owner: Option>, 29 | last_class: Option, 30 | origin: &Option>, 31 | default_ttl: Option) -> ScanResult { 32 | let owner = try!(MasterRecord::scan_owner(stream, last_owner, 33 | origin)); 34 | let (ttl, class) = try!(MasterRecord::scan_ttl_class(stream, 35 | default_ttl, 36 | last_class)); 37 | let rtype = try!(Rtype::scan(stream)); 38 | let rdata = try!(MasterRecordData::scan(rtype, stream, 39 | map_origin(origin))); 40 | try!(stream.scan_newline()); 41 | Ok(MasterRecord::new(owner, class, ttl, rdata)) 42 | } 43 | 44 | /// Scans the owner. 45 | /// 46 | /// Returns new owner and origin. 47 | fn scan_owner(stream: &mut S, 48 | last_owner: Option>, 49 | origin: &Option>) 50 | -> ScanResult> { 51 | let pos = stream.pos(); 52 | if let Ok(()) = stream.scan_space() { 53 | if let Some(owner) = last_owner { Ok(owner) } 54 | else { Err(ScanError::Syntax(SyntaxError::NoLastOwner, pos)) } 55 | } 56 | else if let Ok(()) = stream.skip_literal(b"@") { 57 | if let Some(ref origin) = *origin { Ok(origin.clone()) } 58 | else { Err(ScanError::Syntax(SyntaxError::NoOrigin, pos)) } 59 | } 60 | else { 61 | Ok(Rc::new(try!(stream.scan_dname(map_origin(origin))))) 62 | } 63 | } 64 | 65 | fn scan_ttl_class(stream: &mut S, default_ttl: Option, 66 | last_class: Option) 67 | -> ScanResult<(u32, Class)> { 68 | let pos = stream.pos(); 69 | let (ttl, class) = match stream.scan_u32() { 70 | Ok(ttl) => { 71 | match Class::scan(stream) { 72 | Ok(class) => { 73 | (Some(ttl), Some(class)) 74 | } 75 | Err(_) => (Some(ttl), None) 76 | } 77 | } 78 | Err(_) => { 79 | match Class::scan(stream) { 80 | Ok(class) => { 81 | match stream.scan_u32() { 82 | Ok(ttl) => { 83 | (Some(ttl), Some(class)) 84 | } 85 | Err(_) => (None, Some(class)) 86 | } 87 | } 88 | Err(_) => (None, None) 89 | } 90 | } 91 | }; 92 | let ttl = match ttl.or(default_ttl) { 93 | Some(ttl) => ttl, 94 | None => { 95 | return Err(ScanError::Syntax(SyntaxError::NoDefaultTtl, pos)) 96 | } 97 | }; 98 | let class = match class.or(last_class) { 99 | Some(class) => class, 100 | None => { 101 | return Err(ScanError::Syntax(SyntaxError::NoLastClass, pos)) 102 | } 103 | }; 104 | Ok((ttl, class)) 105 | } 106 | } 107 | 108 | impl fmt::Display for MasterRecord { 109 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 110 | write!(f, "{} {} {} {} {}", 111 | self.owner, self.ttl, self.class, 112 | self.rdata.rtype(), self.rdata) 113 | } 114 | } 115 | 116 | 117 | pub fn map_origin(origin: &Option>) -> Option<&DNameSlice> { 118 | match *origin { 119 | Some(ref rc) => Some(rc), 120 | None => None 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/rdata/generic.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | use ::master::{Scanner, ScanResult, SyntaxError}; 4 | 5 | /// Scan generic master format record data into a bytes buf. 6 | /// 7 | /// This function *only* scans the generic record data format defined 8 | /// in [RFC 3597]. 9 | /// 10 | /// [RFC 3597]: https:://tools.ietf.org/html/rfc3597 11 | /// [`domain::rdata::scan_into()`]: ../../rdata/fn.scan_into.html 12 | pub fn scan(scanner: &mut S) -> ScanResult> { 13 | let mut target = Vec::new(); 14 | try!(scanner.skip_literal(b"\\#")); 15 | let mut len = try!(scanner.scan_u16()); 16 | target.reserve(len as usize); 17 | while len > 0 { 18 | try!(scanner.scan_hex_word(|v| { 19 | if len == 0 { Err(SyntaxError::LongGenericData) } 20 | else { 21 | target.push(v); 22 | len -= 1; 23 | Ok(()) 24 | } 25 | })) 26 | } 27 | Ok(target) 28 | } 29 | 30 | pub fn fmt(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { 31 | let mut some = false; 32 | for chunk in data.chunks(2) { 33 | if some { try!(write!(f, " ")); } 34 | else { some = true } 35 | try!(write!(f, "{:02x}", chunk[0])); 36 | if let Some(ch) = chunk.get(1) { 37 | try!(write!(f, "{:02x}", ch)); 38 | } 39 | } 40 | Ok(()) 41 | } 42 | -------------------------------------------------------------------------------- /src/rdata/macros.rs: -------------------------------------------------------------------------------- 1 | //! Macros for use in rdata definitions. 2 | //! 3 | //! These macros are not public but are used by the super module only. They 4 | //! are here so that `mod.rs` doesn’t become too unwieldly. 5 | 6 | macro_rules! master_types { 7 | ( $( $module:ident::{ $( $rtype:ident => $full_rtype:ty, )* })* ) => { 8 | $( 9 | pub use self::$module::{ $( $rtype ),* }; 10 | )* 11 | 12 | /// An enum with all the record data that can appear in master files. 13 | /// 14 | /// This enum contains variants for all the implemented record data 15 | /// types in their owned form plus the `Generic` variant record data 16 | /// of any other type. 17 | #[derive(Clone, Debug)] 18 | pub enum MasterRecordData { 19 | $( 20 | $( 21 | $rtype($full_rtype), 22 | )* 23 | )* 24 | Generic(::iana::Rtype, Vec), 25 | } 26 | 27 | impl MasterRecordData { 28 | pub fn scan(rtype: ::iana::Rtype, scanner: &mut S, 29 | origin: Option<&::bits::name::DNameSlice>) 30 | -> ::master::ScanResult 31 | where S: ::master::Scanner { 32 | // First try the generic format for everything. 33 | let err = match ::rdata::generic::scan(scanner) { 34 | Ok(some) => { 35 | return Ok(MasterRecordData::Generic(rtype, some)) 36 | } 37 | Err(err) => err 38 | }; 39 | // Now see if we have a master type that can parse this for 40 | // real. 41 | match rtype { 42 | $( 43 | $( 44 | ::iana::Rtype::$rtype => { 45 | $rtype::scan(scanner, origin) 46 | .map(MasterRecordData::$rtype) 47 | } 48 | )* 49 | )* 50 | // We don’t. Good thing we kept the error. 51 | _ => Err(err) 52 | } 53 | } 54 | } 55 | 56 | impl ::bits::RecordData for MasterRecordData { 57 | fn rtype(&self) -> ::iana::Rtype { 58 | match *self { 59 | $( 60 | $( 61 | MasterRecordData::$rtype(ref data) => { 62 | data.rtype() 63 | } 64 | )* 65 | )* 66 | MasterRecordData::Generic(rtype, _) => rtype 67 | } 68 | } 69 | 70 | fn compose(&self, mut target: C) -> ::bits::ComposeResult<()> 71 | where C: AsMut<::bits::Composer> { 72 | match *self { 73 | $( 74 | $( 75 | MasterRecordData::$rtype(ref data) => { 76 | data.compose(target) 77 | } 78 | )* 79 | )* 80 | MasterRecordData::Generic(_, ref data) => { 81 | target.as_mut().compose_bytes(data) 82 | } 83 | } 84 | } 85 | } 86 | 87 | impl ::std::fmt::Display for MasterRecordData { 88 | fn fmt(&self, f: &mut ::std::fmt::Formatter) 89 | -> ::std::fmt::Result { 90 | match *self { 91 | $( 92 | $( 93 | MasterRecordData::$rtype(ref data) => { 94 | ::std::fmt::Display::fmt(data, f) 95 | } 96 | )* 97 | )* 98 | MasterRecordData::Generic(_, ref data) => { 99 | ::rdata::generic::fmt(data, f) 100 | } 101 | } 102 | } 103 | } 104 | 105 | /// Helper function for `fmt_rdata()`. 106 | /// 107 | /// This function contains the part of `fmt_rdata()` that needs to 108 | /// be generated via the `master_types!` macro. 109 | fn fmt_master_data(rtype: ::iana::Rtype, 110 | parser: &mut ::bits::Parser, 111 | f: &mut ::std::fmt::Formatter) 112 | -> Result, ::std::fmt::Error> { 113 | use bits::rdata::ParsedRecordData; 114 | 115 | match rtype { 116 | $( 117 | $( 118 | ::iana::Rtype::$rtype => { 119 | match ::rdata::parsed::$rtype::parse(rtype, 120 | parser) { 121 | Ok(None) => unreachable!(), 122 | Ok(Some(data)) => { 123 | ::std::fmt::Display::fmt(&data, f) 124 | .map(Some) 125 | } 126 | Err(err) => { 127 | write!(f, "", err) 128 | .map(Some) 129 | } 130 | } 131 | } 132 | )* 133 | )* 134 | _ => Ok(None) 135 | } 136 | } 137 | } 138 | } 139 | 140 | macro_rules! pseudo_types { 141 | ( $( $module:ident::{ $( $rtype:ident ),* };)* ) => { 142 | $( 143 | pub use self::$module::{ $( $rtype ),* }; 144 | )* 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/rdata/mod.rs: -------------------------------------------------------------------------------- 1 | //! Resource data implementations. 2 | //! 3 | //! This module will eventually contain implementations for the record data 4 | //! for all defined resource record types. 5 | //! 6 | //! The types are named identically to the [`Rtype`] variant they implement. 7 | //! They are grouped into submodules for the RFCs they are defined in. All 8 | //! types are also re-exported at the top level here. Ie., for the AAAA 9 | //! record type, you can simple `use domain::rdata::Aaaa` instead of 10 | //! `use domain::rdata::rfc3596::Aaaa` which nobody could possibly remember. 11 | //! There are, however, some helper data types defined here and there which 12 | //! are not re-exported to keep things somewhat tidy. 13 | //! 14 | //! See the [`Rtype`] enum for the complete set of record types and, 15 | //! consequently, those types that are still missing. 16 | //! 17 | //! [`Rtype`]: ../iana/enum.Rtype.html 18 | 19 | pub mod rfc1035; 20 | pub mod rfc2782; 21 | pub mod rfc3596; 22 | 23 | #[macro_use] mod macros; 24 | mod generic; 25 | 26 | use ::bits::{CharStrBuf, DNameBuf}; 27 | 28 | // The master_types! macro (defined in self::macros) creates the 29 | // MasterRecordData enum produced when parsing master files (aka zone files). 30 | // 31 | // Include all record types that can occur in master files. Place the name of 32 | // the variant (identical to the type name) on the left side of the double 33 | // arrow and the name of the type on the right. If the type is generic, use 34 | // the owned version. 35 | // 36 | // The macro creates the re-export of the record data type. 37 | master_types!{ 38 | rfc1035::{ 39 | A => A, 40 | Cname => Cname, 41 | Hinfo => Hinfo, 42 | Mb => Mb, 43 | Md => Md, 44 | Mf => Mf, 45 | Mg => Mg, 46 | Minfo => Minfo, 47 | Mr => Mr, 48 | Mx => Mx, 49 | Ns => Ns, 50 | Ptr => Ptr, 51 | Soa => Soa, 52 | Txt => Txt>, 53 | Wks => Wks, 54 | } 55 | rfc2782::{ 56 | Srv => Srv, 57 | } 58 | rfc3596::{ 59 | Aaaa => Aaaa, 60 | } 61 | } 62 | 63 | // The pseudo_types! macro (defined in self::macros) creates the re-exports 64 | // for all the types not part of master_types! above. 65 | pseudo_types!{ 66 | rfc1035::{Null}; 67 | //rfc6891::{Opt}; 68 | } 69 | 70 | /// Formats record data from a message parser in master file format. 71 | /// 72 | /// This helper function formats the record data at the start of `parser` 73 | /// using the formatter `f`. It assumes that the record data is for a 74 | /// record of record type `rtype`. 75 | /// 76 | /// If the record type is known, the function tries to use the type’s 77 | /// proper master data format. Otherwise the generic format is used. 78 | pub fn fmt_rdata(rtype: ::iana::Rtype, parser: &mut ::bits::Parser, 79 | f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 80 | match try!(fmt_master_data(rtype, parser, f)) { 81 | Some(res) => Ok(res), 82 | None => { 83 | let mut parser = parser.clone(); 84 | let len = parser.remaining(); 85 | let data = parser.parse_bytes(len).unwrap(); 86 | generic::fmt(data, f) 87 | } 88 | } 89 | } 90 | 91 | /// Parsed versions of all record data types. 92 | /// 93 | /// This module defines or re-exports type aliases for all record data 94 | /// types that use parsed domain names and references to bytes slices where 95 | /// applicable. For convenience, it also includes re-exports for those types 96 | /// that are not in fact generic. 97 | /// 98 | /// Use the types from this module when working with wire format DNS messages. 99 | pub mod parsed { 100 | pub use super::rfc1035::parsed::*; 101 | pub use super::rfc3596::Aaaa; 102 | pub type Srv<'a> = super::rfc2782::Srv<::bits::ParsedDName<'a>>; 103 | } 104 | 105 | /// Owned versions of all record data types. 106 | /// 107 | /// This module defines or re-exports type aliases for all record data 108 | /// types using owned data only. For convenience, it also includes re-exports 109 | /// for those types that are not generic. 110 | /// 111 | /// Use the types from this module if you are working with master file data 112 | /// or if you are constructing your own values. 113 | pub mod owned { 114 | pub use super::rfc1035::owned::*; 115 | pub use super::rfc3596::Aaaa; 116 | pub type Srv = super::rfc2782::Srv<::bits::DNameBuf>; 117 | } 118 | -------------------------------------------------------------------------------- /src/rdata/rfc2782.rs: -------------------------------------------------------------------------------- 1 | //! Record data from [RFC 2782]. 2 | //! 3 | //! This RFC defines the Srv record type. 4 | //! 5 | //! [RFC 2782]: https://tools.ietf.org/html/rfc2782 6 | 7 | use std::fmt; 8 | use ::bits::{Composer, ComposeResult, DNameSlice, ParsedRecordData, 9 | Parser, ParseResult, RecordData, DName, DNameBuf, ParsedDName}; 10 | use ::iana::Rtype; 11 | use ::master::{Scanner, ScanResult}; 12 | 13 | 14 | //------------ Srv --------------------------------------------------------- 15 | 16 | #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] 17 | pub struct Srv { 18 | priority: u16, 19 | weight: u16, 20 | port: u16, 21 | target: N 22 | } 23 | 24 | impl Srv { 25 | pub fn new(priority: u16, weight: u16, port: u16, target: N) -> Self { 26 | Srv { priority: priority, weight: weight, port: port, target: target } 27 | } 28 | 29 | pub fn priority(&self) -> u16 { self.priority } 30 | pub fn weight(&self) -> u16 { self.weight } 31 | pub fn port(&self) -> u16 { self.port } 32 | pub fn target(&self) -> &N { &self.target } 33 | } 34 | 35 | impl<'a> Srv> { 36 | fn parse_always(parser: &mut Parser<'a>) -> ParseResult { 37 | Ok(Self::new(try!(parser.parse_u16()), 38 | try!(parser.parse_u16()), 39 | try!(parser.parse_u16()), 40 | try!(ParsedDName::parse(parser)))) 41 | } 42 | } 43 | 44 | impl Srv { 45 | pub fn scan(scanner: &mut S, origin: Option<&DNameSlice>) 46 | -> ScanResult { 47 | Ok(Self::new(try!(scanner.scan_u16()), 48 | try!(scanner.scan_u16()), 49 | try!(scanner.scan_u16()), 50 | try!(DNameBuf::scan(scanner, origin)))) 51 | } 52 | } 53 | 54 | impl RecordData for Srv { 55 | fn rtype(&self) -> Rtype { Rtype::Srv } 56 | 57 | fn compose>(&self, mut target: C) 58 | -> ComposeResult<()> { 59 | target.as_mut().compose_u16(self.priority)?; 60 | target.as_mut().compose_u16(self.weight)?; 61 | target.as_mut().compose_u16(self.port)?; 62 | self.target.compose(target) 63 | } 64 | } 65 | 66 | impl<'a> ParsedRecordData<'a> for Srv> { 67 | fn parse(rtype: Rtype, parser: &mut Parser<'a>) -> ParseResult> { 68 | if rtype == Rtype::Srv { Srv::parse_always(parser).map(Some) } 69 | else { Ok(None) } 70 | } 71 | } 72 | 73 | impl fmt::Display for Srv { 74 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 75 | write!(f, "{} {} {} {}", self.priority, self.weight, self.port, self.target) 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/rdata/rfc3596.rs: -------------------------------------------------------------------------------- 1 | //! Record data from [RFC 3596]. 2 | //! 3 | //! This RFC defines the Aaaa record type. 4 | //! 5 | //! [RFC 3596]: https://tools.ietf.org/html/rfc3596 6 | 7 | use std::fmt; 8 | use std::net::Ipv6Addr; 9 | use std::str::FromStr; 10 | use ::bits::{Composable, Composer, ComposeResult, DNameSlice, ParsedRecordData, 11 | Parser, ParseResult, RecordData}; 12 | use ::iana::Rtype; 13 | use ::master::{Scanner, ScanResult}; 14 | 15 | 16 | //------------ Aaaa --------------------------------------------------------- 17 | 18 | #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] 19 | pub struct Aaaa { 20 | addr: Ipv6Addr 21 | } 22 | 23 | impl Aaaa { 24 | pub fn new(addr: Ipv6Addr) -> Aaaa { 25 | Aaaa { addr: addr } 26 | } 27 | 28 | pub fn addr(&self) -> Ipv6Addr { self.addr } 29 | pub fn set_addr(&mut self, addr: Ipv6Addr) { self.addr = addr } 30 | 31 | fn parse_always(parser: &mut Parser) -> ParseResult { 32 | Ok(Aaaa::new(Ipv6Addr::new(try!(parser.parse_u16()), 33 | try!(parser.parse_u16()), 34 | try!(parser.parse_u16()), 35 | try!(parser.parse_u16()), 36 | try!(parser.parse_u16()), 37 | try!(parser.parse_u16()), 38 | try!(parser.parse_u16()), 39 | try!(parser.parse_u16())))) 40 | } 41 | 42 | pub fn scan(scanner: &mut S, _origin: Option<&DNameSlice>) 43 | -> ScanResult { 44 | scanner.scan_str_phrase(|slice| { 45 | let addr = try!(Ipv6Addr::from_str(slice)); 46 | Ok(Aaaa::new(addr)) 47 | }) 48 | } 49 | } 50 | 51 | impl RecordData for Aaaa { 52 | fn rtype(&self) -> Rtype { Rtype::Aaaa } 53 | 54 | fn compose>(&self, mut target: C) 55 | -> ComposeResult<()> { 56 | for i in &self.addr.segments() { 57 | try!(i.compose(target.as_mut())); 58 | } 59 | Ok(()) 60 | } 61 | } 62 | 63 | impl<'a> ParsedRecordData<'a> for Aaaa { 64 | fn parse(rtype: Rtype, parser: &mut Parser) -> ParseResult> { 65 | if rtype == Rtype::Aaaa { Aaaa::parse_always(parser).map(Some) } 66 | else { Ok(None) } 67 | } 68 | } 69 | 70 | impl fmt::Display for Aaaa { 71 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 72 | self.addr.fmt(f) 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/resolv/error.rs: -------------------------------------------------------------------------------- 1 | //! Resolver errors and results. 2 | 3 | use std::error; 4 | use std::io; 5 | use std::fmt; 6 | use std::result; 7 | use ::bits::{ComposeError, ParseError}; 8 | use ::iana::Rcode; 9 | 10 | 11 | //------------ Error --------------------------------------------------------- 12 | 13 | /// An error happened during a query. 14 | /// 15 | // XXX While this type is currently used all over the resolver, it really 16 | // is the error that is to be produced by lookups. We need to refactor 17 | // this a bit and create specific error types for the various stages 18 | // of processing. 19 | #[derive(Debug)] 20 | pub enum Error { 21 | /// The question was broken. 22 | Question(ComposeError), 23 | 24 | /// All queries timed out. 25 | Timeout, 26 | 27 | /// All responses for a query were negative. 28 | NoName, 29 | 30 | /// At least one response was received but none was secure. 31 | NoSecureAnswers, 32 | 33 | /// At least one response was received but all were bogus. 34 | AllBogusAnswers, 35 | 36 | /// An IO error stopped queries from succeeding at all. 37 | Io(io::Error), 38 | } 39 | 40 | 41 | impl Error { 42 | /// Finds the most appropriate error for two failed queries. 43 | #[allow(match_same_arms)] 44 | pub fn merge(self, other: Self) -> Self { 45 | use self::Error::*; 46 | 47 | match (self, other) { 48 | (Question(err), _) => Question(err), 49 | 50 | (Timeout, Io(_)) => Timeout, 51 | (Timeout, other) => other, 52 | 53 | (NoName, NoSecureAnswers) => NoSecureAnswers, 54 | (NoName, AllBogusAnswers) => AllBogusAnswers, 55 | (NoName, _) => NoName, 56 | 57 | (NoSecureAnswers, _) => NoSecureAnswers, 58 | 59 | (AllBogusAnswers, NoSecureAnswers) => NoSecureAnswers, 60 | (AllBogusAnswers, _) => AllBogusAnswers, 61 | 62 | (Io(_), other) => other 63 | } 64 | } 65 | } 66 | 67 | 68 | //--- Error 69 | 70 | impl error::Error for Error { 71 | fn description(&self) -> &str { 72 | use self::Error::*; 73 | 74 | match *self { 75 | Question(ref error) => error.description(), 76 | NoName => "all responses were negative", 77 | Timeout => "all queries timed out", 78 | NoSecureAnswers => "no received response was secure", 79 | AllBogusAnswers => "all received responses were bogus", 80 | Io(ref error) => error.description() 81 | } 82 | } 83 | } 84 | 85 | 86 | //--- From 87 | 88 | impl From for Error { 89 | fn from(rcode: Rcode) -> Error { 90 | match rcode { 91 | Rcode::NXDomain => Error::NoName, 92 | _ => Error::Timeout, 93 | } 94 | } 95 | } 96 | 97 | impl From for Error { 98 | fn from(error: ComposeError) -> Error { 99 | Error::Question(error) 100 | } 101 | } 102 | 103 | impl From for Error { 104 | fn from(error: io::Error) -> Error { 105 | Error::Io(error) 106 | } 107 | } 108 | 109 | impl From for Error { 110 | fn from(error: ParseError) -> Error { 111 | Error::Io(io::Error::from(error)) 112 | } 113 | } 114 | 115 | //--- From for io::Error 116 | 117 | impl From for io::Error { 118 | fn from(error: Error) -> io::Error { 119 | io::Error::new(io::ErrorKind::Other, error) 120 | } 121 | } 122 | 123 | 124 | //--- Display 125 | 126 | impl fmt::Display for Error { 127 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 128 | use std::error::Error; 129 | 130 | self.description().fmt(f) 131 | } 132 | } 133 | 134 | 135 | //------------ Result -------------------------------------------------------- 136 | 137 | /// The result type of a query. 138 | pub type Result = result::Result; 139 | 140 | -------------------------------------------------------------------------------- /src/resolv/intro.rs: -------------------------------------------------------------------------------- 1 | //! Resolver Architecture Documentation 2 | //! 3 | //! This module does not contain any code. It is intended for more 4 | //! detailed documentation of the resolver. Currently, that is limited to 5 | //! a short introduction to its architecture. 6 | //! 7 | //! 8 | //! # What’s in a Resolver? 9 | //! 10 | //! Roughly speaking, the task of a resolver is to answer a question using 11 | //! information stored in the DNS. We shall call this question a *lookup.* 12 | //! There is different lookups for different questions. For example, finding 13 | //! all IP addresses for a given hostname is such a lookup. Finding the IP 14 | //! addresses of the mail server for a given domain is another, somewhat more 15 | //! complex lookup. 16 | //! 17 | //! DNS is a relatively simple key-value store: All information is keyed by 18 | //! a tripel of a domain name, a record type, and a class. The values are a 19 | //! set of binary strings who will be interpreted according to rules defined 20 | //! for each record type. One such entry is called a *resource record set,* 21 | //! commonly shortened to *RRset.* 22 | //! 23 | //! Most lookups will require information from more than one such RRset. 24 | //! For example, there are two types of IP addresses: IPv4 and IPv6 25 | //! addresses. Each type has its own record type, so there are two RRsets 26 | //! to consider when determining all addresses assigned to a host. 27 | //! 28 | //! In this case, the two RRsets can be looked up in parallel. In case of the 29 | //! mail server lookup, we first need to determine the host name of the mail 30 | //! server responsible for the domain. There is a record type and hence a 31 | //! RRset for this purpose. Once we have that, we can look up the IP addresses 32 | //! for that host in parallel. 33 | //! 34 | //! In other words, a lookup performs a series of steps each consisting of 35 | //! asking the DNS for one or more RRsets in parallel. 36 | //! 37 | //! Such a request for a specific RRset is called a *query.* Since DNS is a 38 | //! distributed system, the first step of a query would be finding out where 39 | //! exactly the RRset is stored. However, we are implementing a stub resolver 40 | //! which is configured with a set of DNS servers that do this hunt for it. 41 | //! The stub resolver simply asks those configured servers for the RRset and 42 | //! if they all fail to find it, it fails too. 43 | //! 44 | //! Since DNS prefers to use the unreliable UDP as transport protocol, the 45 | //! typical strategy is to ask the first server on the list and wait for a 46 | //! bit. If no answer arrives, ask the second server and wait again. If all 47 | //! servers have been asked and none has answered in due time, repeat the 48 | //! process for a number of times and finally fail. Alternatives are to start 49 | //! with a different server every time or to ask all servers at once. 50 | //! Under some circumstances, the resolver can also fall back to using TCP 51 | //! instead. Plus, there is an effort underway to encrypt the DNS connections. 52 | //! 53 | //! Which all is to say that a query may have to ask different servers for an 54 | //! RRset, potentially using different transport protocols. For our own 55 | //! purposes, we shall henceforth call the process of asking one specific 56 | //! server over one specific transport protocol a *request.* 57 | //! 58 | //! The *resolver,* finally, collects all information necessary to be able 59 | //! to perform queries. It knows which servers to use with which protocols 60 | //! and has additional configuration information that is used to perform 61 | //! queries. 62 | //! 63 | //! 64 | //! # A Resolver using Futures and Tokio 65 | //! 66 | 67 | -------------------------------------------------------------------------------- /src/resolv/lookup/addr.rs: -------------------------------------------------------------------------------- 1 | //! Looking up host names for addresses. 2 | 3 | use std::mem; 4 | use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 5 | use std::str::FromStr; 6 | use futures::{Async, Future, Poll}; 7 | use ::bits::name::{DNameBuf, Label, ParsedDName}; 8 | use ::bits::message::{MessageBuf, RecordIter}; 9 | use ::iana::{Class, Rtype}; 10 | use ::rdata::parsed::Ptr; 11 | use super::super::conf::ResolvOptions; 12 | use super::super::error::Error; 13 | use super::super::Query; 14 | use super::super::Resolver; 15 | 16 | 17 | //------------ lookup_addr --------------------------------------------------- 18 | 19 | /// Creates a future that resolves into the host names for an IP address. 20 | /// 21 | /// The future will query DNS using the resolver represented by `resolv`. 22 | /// It will query DNS only and not consider any other database the system 23 | /// may have. 24 | /// 25 | /// The value returned upon success can be turned into an iterator over 26 | /// host names via its `iter()` method. This is due to lifetime issues. 27 | pub fn lookup_addr(resolv: Resolver, addr: IpAddr) -> LookupAddr { 28 | let name = dname_from_addr(addr, resolv.options()); 29 | LookupAddr(Query::new(resolv, (name, Rtype::Ptr, Class::In))) 30 | } 31 | 32 | 33 | //------------ LookupAddr ---------------------------------------------------- 34 | 35 | /// The future for [`lookup_addr()`]. 36 | /// 37 | /// [`lookup_addr()`]: fn.lookup_addr.html 38 | pub struct LookupAddr(Query); 39 | 40 | impl Future for LookupAddr { 41 | type Item = FoundAddrs; 42 | type Error = Error; 43 | 44 | fn poll(&mut self) -> Poll { 45 | Ok(Async::Ready(FoundAddrs(try_ready!(self.0.poll())))) 46 | } 47 | } 48 | 49 | 50 | //------------ FoundAddrs ---------------------------------------------------- 51 | 52 | /// The success type of the `lookup_addr()` function. 53 | /// 54 | /// The only purpose of this type is to return an iterator over host names 55 | /// via its `iter()` method. 56 | pub struct FoundAddrs(MessageBuf); 57 | 58 | impl FoundAddrs { 59 | /// Returns an iterator over the host names. 60 | pub fn iter(&self) -> FoundAddrsIter { 61 | FoundAddrsIter { 62 | name: self.0.canonical_name(), 63 | answer: self.0.answer().ok().map(|sec| sec.limit_to::()) 64 | } 65 | } 66 | } 67 | 68 | 69 | //------------ FoundAddrsIter ------------------------------------------------ 70 | 71 | /// An iterator over host names returned by address lookup. 72 | pub struct FoundAddrsIter<'a> { 73 | name: Option>, 74 | answer: Option>> 75 | } 76 | 77 | impl<'a> Iterator for FoundAddrsIter<'a> { 78 | type Item = ParsedDName<'a>; 79 | 80 | #[allow(while_let_on_iterator)] 81 | fn next(&mut self) -> Option { 82 | let name = if let Some(ref name) = self.name { name } 83 | else { return None }; 84 | let answer = if let Some(ref mut answer) = self.answer { answer } 85 | else { return None }; 86 | while let Some(Ok(record)) = answer.next() { 87 | if record.name() == name { 88 | return Some(record.data().ptrdname().clone()) 89 | } 90 | } 91 | None 92 | } 93 | } 94 | 95 | 96 | //------------ Helper Functions --------------------------------------------- 97 | 98 | /// Translates an IP address into a domain name. 99 | fn dname_from_addr(addr: IpAddr, opts: &ResolvOptions) -> DNameBuf { 100 | match addr { 101 | IpAddr::V4(addr) => dname_from_v4(addr), 102 | IpAddr::V6(addr) => dname_from_v6(addr, opts) 103 | } 104 | } 105 | 106 | /// Translates an IPv4 address into a domain name. 107 | fn dname_from_v4(addr: Ipv4Addr) -> DNameBuf { 108 | let octets = addr.octets(); 109 | DNameBuf::from_str(&format!("{}.{}.{}.{}.in-addr.arpa.", octets[3], 110 | octets[2], octets[1], octets[0])).unwrap() 111 | } 112 | 113 | /// Translate an IPv6 address into a domain name. 114 | /// 115 | /// As there are several ways to do this, the functions depends on 116 | /// resolver options, namely `use_bstring` and `use_ip6dotin`. 117 | fn dname_from_v6(addr: Ipv6Addr, opts: &ResolvOptions) -> DNameBuf { 118 | let mut res = DNameBuf::new(); 119 | if opts.use_bstring { 120 | // XXX Use Ipv6Addr::octets once that is stable. 121 | let mut segments = addr.segments(); 122 | for item in &mut segments { 123 | *item = item.to_be() 124 | } 125 | let bytes: [u8; 16] = unsafe { mem::transmute(segments) }; 126 | res.push_binary(16, &bytes).unwrap(); 127 | } 128 | else { 129 | for item in addr.segments().iter().rev() { 130 | let text = format!("{:04x}", item); 131 | let text = text.as_bytes(); 132 | res.push_normal(&text[3..4]).unwrap(); 133 | res.push_normal(&text[2..3]).unwrap(); 134 | res.push_normal(&text[1..2]).unwrap(); 135 | res.push_normal(&text[0..1]).unwrap(); 136 | } 137 | } 138 | res.push_normal(b"ip6").unwrap(); 139 | if opts.use_ip6dotint { 140 | res.push_normal(b"int").unwrap(); 141 | } 142 | else { 143 | res.push_normal(b"arpa").unwrap(); 144 | } 145 | res.push(Label::root()).unwrap(); 146 | res 147 | } 148 | 149 | -------------------------------------------------------------------------------- /src/resolv/lookup/mod.rs: -------------------------------------------------------------------------------- 1 | //! Lookup functions and related types. 2 | //! 3 | //! This module collects a number of more or less complex lookups that 4 | //! implement applications of the DNS. 5 | 6 | pub use self::addr::lookup_addr; 7 | pub use self::host::lookup_host; 8 | pub use self::records::lookup_records; 9 | pub use self::srv::lookup_srv; 10 | 11 | pub mod addr; 12 | pub mod host; 13 | pub mod records; 14 | pub mod search; 15 | pub mod srv; 16 | -------------------------------------------------------------------------------- /src/resolv/lookup/records.rs: -------------------------------------------------------------------------------- 1 | //! Looking up raw records. 2 | 3 | use futures::{Async, Future, Poll}; 4 | use ::bits::{DNameSlice, MessageBuf}; 5 | use ::iana::{Rtype, Class}; 6 | use super::super::{Query, Resolver}; 7 | use super::super::error::Error; 8 | use super::search::SearchIter; 9 | 10 | 11 | //------------ lookup_records ------------------------------------------------ 12 | 13 | /// Creates a future that looks up DNS records. 14 | /// 15 | /// The future will use the given resolver to perform a DNS query for the 16 | /// records of type `rtype` associated with `name` in `class`. 17 | /// This differs from calling `resolv.query()` directly in that it can treat 18 | /// relative names. In this case, the resolver configuration is considered 19 | /// to translate the name into a series of absolute names. If you want to 20 | /// find out the name that resulted in a successful answer, you can look at 21 | /// the query in the resulting message. 22 | pub fn lookup_records(resolver: Resolver, name: N, rtype: Rtype, 23 | class: Class) -> LookupRecords 24 | where N: AsRef { 25 | let name = name.as_ref(); 26 | let mut search = SearchIter::new(resolver.clone(), name); 27 | let search_name = search.as_mut().map(|s| s.next().unwrap()); 28 | let query_name = match search_name { 29 | Some(ref name) => name, 30 | None => name 31 | }; 32 | let query = resolver.clone().query((query_name, rtype, class)); 33 | LookupRecords { 34 | resolver: resolver, 35 | query: query, 36 | search: search, 37 | rtype: rtype, 38 | class: class 39 | } 40 | } 41 | 42 | 43 | //------------ LookupRecords ------------------------------------------------- 44 | 45 | /// The future returned by [`lookup_records()`]. 46 | /// 47 | /// [`lookup_records()`]: fn.lookup_records.html 48 | pub struct LookupRecords { 49 | /// The resolver to run queries on. 50 | resolver: Resolver, 51 | 52 | /// The current querry. 53 | query: Query, 54 | 55 | /// An optional search list iterator for searching a name. 56 | search: Option, 57 | 58 | /// The resource record type to search for. 59 | rtype: Rtype, 60 | 61 | /// The class to search for. 62 | class: Class, 63 | } 64 | 65 | 66 | //--- Future 67 | 68 | impl Future for LookupRecords { 69 | type Item = MessageBuf; 70 | type Error = Error; 71 | 72 | fn poll(&mut self) -> Poll { 73 | let err = match self.query.poll() { 74 | Ok(Async::NotReady) => return Ok(Async::NotReady), 75 | Ok(Async::Ready(item)) => return Ok(Async::Ready(item)), 76 | Err(err) => err 77 | }; 78 | let name = match self.search { 79 | None => return Err(err), 80 | Some(ref mut search) => { 81 | match search.next() { 82 | None => return Err(err), 83 | Some(name) => name, 84 | } 85 | } 86 | }; 87 | self.query = self.resolver.clone() 88 | .query((name, self.rtype, self.class)); 89 | self.poll() 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /src/resolv/lookup/search.rs: -------------------------------------------------------------------------------- 1 | //! Working with the search list. 2 | 3 | use ::bits::{DNameBuf, DNameSlice}; 4 | use super::super::Resolver; 5 | 6 | 7 | //------------ SearchIter ---------------------------------------------------- 8 | 9 | /// An iterator gained from applying a search list to a domain name. 10 | /// 11 | /// The iterator represents how a resolver attempts to derive an absolute 12 | /// domain name from a relative name. 13 | /// 14 | /// For this purpose, the resolver’s configuration contains a search list, 15 | /// a list of absolute domain names that are appened in turn to the domain 16 | /// name. In addition, if the name contains enough dots (specifically, 17 | /// `ResolvConf::ndots` which defaults to just one) it is first tried as if 18 | /// it were an absolute by appending the root labels. 19 | pub struct SearchIter { 20 | /// The base name to work with. 21 | name: DNameBuf, 22 | 23 | /// The resolver to use for looking up the search list. 24 | resolv: Resolver, 25 | 26 | /// The state of working through the search list. 27 | state: SearchState, 28 | } 29 | 30 | enum SearchState { 31 | /// The next value is to be the name treated as an absolute name. 32 | Absolute, 33 | 34 | /// The next value is to be item with the contained value as index in 35 | /// the resolver’s search list. 36 | Search(usize), 37 | 38 | /// All options are exhausted. 39 | Done, 40 | } 41 | 42 | 43 | impl SearchIter { 44 | /// Creates a new search iterator. 45 | /// 46 | /// The iterator will yield absolute domain names for `name` based on 47 | /// the configuration of the given resolver. 48 | pub fn new(resolv: Resolver, name: &DNameSlice) -> Option { 49 | let state = match name.ndots() { 50 | None => { 51 | // The name is absolute, no searching is necessary. 52 | return None 53 | } 54 | Some(n) if n >= resolv.conf().ndots => { 55 | // We have the required amount of dots to start with treating 56 | // the name as an absolute. 57 | SearchState::Absolute 58 | } 59 | _ => { 60 | // We don’t have enough dots. Start with the search list 61 | // right away. 62 | SearchState::Search(0) 63 | } 64 | }; 65 | Some(SearchIter { 66 | name: name.to_owned(), 67 | resolv: resolv, 68 | state: state 69 | }) 70 | } 71 | } 72 | 73 | impl Iterator for SearchIter { 74 | type Item = DNameBuf; 75 | 76 | fn next(&mut self) -> Option { 77 | // The loop is here to quietly skip over all names where joining 78 | // fails. 79 | #[allow(never_loop)] // False positive by Clippy. It totally does loop 80 | loop { 81 | let (res, state) = match self.state { 82 | SearchState::Absolute => { 83 | match self.name.join(&DNameSlice::root()) { 84 | Ok(name) => (Some(name), SearchState::Search(0)), 85 | Err(_) => continue, 86 | } 87 | } 88 | SearchState::Search(pos) => { 89 | if pos >= self.resolv.conf().search.len() { 90 | (None, SearchState::Done) 91 | } 92 | else { 93 | match self.name.join(&self.resolv.conf() 94 | .search[pos]) { 95 | Ok(name) => { 96 | (Some(name), SearchState::Search(pos + 1)) 97 | } 98 | Err(_) => continue, 99 | } 100 | } 101 | } 102 | SearchState::Done => return None 103 | }; 104 | self.state = state; 105 | return res 106 | } 107 | } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/resolv/mod.rs: -------------------------------------------------------------------------------- 1 | //! An asynchronous stub resolver. 2 | //! 3 | //! A resolver is the component in the DNS that answers queries. A stub 4 | //! resolver does so by simply relaying queries to a different resolver 5 | //! chosen from a predefined set. This is how pretty much all user 6 | //! applications use DNS. 7 | //! 8 | //! This module implements a modern, asynchronous stub resolver built on 9 | //! top of [futures] and [tokio]. 10 | //! 11 | //! The module provides ways to create a *resolver* that knows how to 12 | //! process DNS *queries*. A query asks for all the resource records 13 | //! associated with a given triple of a domain name, resource record type, 14 | //! and class (known as a *question*). It is a future resolving to a DNS 15 | //! message with a successful response or an error. Queries can be combined 16 | //! into *lookups* that use the returned resource records to answer more 17 | //! specific enquiries such as all the IP addresses associated with a given 18 | //! host name. The module provides a rich set of common lookups in the 19 | //! [lookup] sub-module. 20 | //! 21 | //! The following gives an introduction into using the resolver. For an 22 | //! introduction into the internal design, please have a look at the [intro] 23 | //! sub-module. 24 | //! 25 | //! 26 | //! # Creating a Resolver 27 | //! 28 | //! The resolver is represented by the [`Resolver`] type. When creating a 29 | //! value of this type, you create all the parts of an actual resolver 30 | //! according to a resolver configuration. Since these parts are handling 31 | //! actual network traffic, the resolver needs a handle to a Tokio reactor 32 | //! into which these parts will be spawned as futures. 33 | //! 34 | //! For the resolver configuration, there’s [`ResolvConf`]. While you can 35 | //! create a value of this type by hand, the more common way is to use your 36 | //! system’s resolver configuration. [`ResolvConf`] implements the `Default` 37 | //! trait doing exactly that by reading `/etc/resolv.conf`. 38 | //! 39 | //! > That probably won’t work on Windows, but, sadly, I have no idea how to 40 | //! > retrieve the resolver configuration there. Some help here would be 41 | //! > very much appreciated. 42 | //! 43 | //! Since using the system configuration is the most common case by far, 44 | //! [`Resolver`]’s `new()` function does just that. So, the easiest way to 45 | //! get a resolver is just this: 46 | //! 47 | //! ```rust,no_run 48 | //! # extern crate domain; 49 | //! # extern crate tokio_core; 50 | //! use domain::resolv::Resolver; 51 | //! use tokio_core::reactor::Core; 52 | //! 53 | //! # fn main() { 54 | //! let core = Core::new().unwrap(); 55 | //! let resolv = Resolver::new(&core.handle()); 56 | //! # } 57 | //! ``` 58 | //! 59 | //! If you do have a configuration, you can use the `from_conf()` function 60 | //! instead. 61 | //! 62 | //! 63 | //! # Using the Resolver: Queries 64 | //! 65 | //! As was mentioned above, the [`Resolver`] doesn’t actually contain the 66 | //! networking parts necessary to answer queries. Instead, it only knows how 67 | //! to contact those parts. Because of this, you can clone the resolver, 68 | //! even pass it to other threads. 69 | //! 70 | //! The main purpose of the resolver, though, is to start queries. This is 71 | //! done through [`Resolver::query()`]. It takes something that can be 72 | //! turned into a question and returns a future that will resolve into 73 | //! either a [`MessageBuf`] with the response to the query or an [`Error`]. 74 | //! Conveniently, a triple of a domain name, a resource record type, and a 75 | //! class is something than can be turned into a question, so you don’t need 76 | //! to build the question from hand. (You will have to convert a string into 77 | //! a domain name from hand since that may fail.) 78 | //! 79 | //! As an example, let’s find out the IPv6 addresses for `www.rust-lang.org`: 80 | //! 81 | //! ```rust,no_run 82 | //! extern crate domain; 83 | //! extern crate futures; 84 | //! extern crate tokio_core; 85 | //! 86 | //! use std::str::FromStr; 87 | //! use domain::bits::DNameBuf; 88 | //! use domain::iana::{Class, Rtype}; 89 | //! use domain::rdata::Aaaa; 90 | //! use domain::resolv::Resolver; 91 | //! use futures::Future; 92 | //! use tokio_core::reactor::Core; 93 | //! 94 | //! fn main() { 95 | //! let mut core = Core::new().unwrap(); 96 | //! let resolv = Resolver::new(&core.handle()); 97 | //! 98 | //! let name = DNameBuf::from_str("www.rust-lang.org.").unwrap(); 99 | //! let addrs = resolv.query((name, Rtype::Aaaa, Class::In)); 100 | //! let response = core.run(addrs).unwrap(); 101 | //! for record in response.answer().unwrap().limit_to::() { 102 | //! println!("{}", record.unwrap()); 103 | //! } 104 | //! } 105 | //! ``` 106 | //! 107 | //! Note the final dot at `"www.rust-lang.org."` making it an absolute domain 108 | //! name. Queries don’t know how to deal with relative names and will error 109 | //! out if given one. 110 | //! 111 | //! 112 | //! # Complex Queries: Lookups 113 | //! 114 | //! Most of the times when you are using DNS you aren’t really interested in a 115 | //! bunch of resource records. You want an answer to a more concrete 116 | //! question. For instance, if you want to know the IP addresses for a 117 | //! host name, you don’t really care that you have to make a query for the 118 | //! `A` records and one for `AAAA` records for that host name. You want the 119 | //! addresses. 120 | //! 121 | //! This is what lookups do. They are functions that take a [`Resolver`] 122 | //! and some additional information and turn that into a future of some 123 | //! specific result. 124 | //! 125 | //! Using [`lookup_host()`], the process of looking up the IP addresses 126 | //! becomes much easier. To update above’s example: 127 | //! 128 | //! ```rust,no_run 129 | //! extern crate domain; 130 | //! extern crate futures; 131 | //! extern crate tokio_core; 132 | //! 133 | //! use std::str::FromStr; 134 | //! use domain::bits::DNameBuf; 135 | //! use domain::resolv::Resolver; 136 | //! use domain::resolv::lookup::lookup_host; 137 | //! use futures::Future; 138 | //! use tokio_core::reactor::Core; 139 | //! 140 | //! fn main() { 141 | //! let mut core = Core::new().unwrap(); 142 | //! let resolv = Resolver::new(&core.handle()); 143 | //! 144 | //! let name = DNameBuf::from_str("www.rust-lang.org").unwrap(); 145 | //! let addrs = lookup_host(resolv, name); 146 | //! let response = core.run(addrs).unwrap(); 147 | //! for addr in response.iter() { 148 | //! println!("{}", addr); 149 | //! } 150 | //! } 151 | //! ``` 152 | //! 153 | //! No more fiddeling with record types and classes and the result can now 154 | //! iterate over IP addresses. And we get both IPv4 and IPv6 addresses to 155 | //! boot. 156 | //! 157 | //! Furthermore, we now can use a relative host name. It will be turned into 158 | //! an absolute name according to the rules set down by the configuration we 159 | //! used when creating the resolver. 160 | //! 161 | //! As an aside, the lookup functions are named after the thing they look 162 | //! up not their result following the example of the standard library. So, 163 | //! when you look for the addresses for the host, you have to use 164 | //! [`lookup_host()`], not [`lookup_addr()`]. 165 | //! 166 | //! Have a look at the [lookup] module for all the lookup functions 167 | //! currently available. 168 | //! 169 | //! 170 | //! # The Run Shortcut 171 | //! 172 | //! If you only want to do a DNS lookup and don’t otherwise use tokio, there 173 | //! is a shortcut through the [`Resolver::run()`] associated function. It 174 | //! takes a closure from a [`Resolver`] to a future and waits while 175 | //! driving the future to completing. In other words, it takes away all the 176 | //! boiler plate from above: 177 | //! 178 | //! ```rust,no_run 179 | //! extern crate domain; 180 | //! 181 | //! use std::str::FromStr; 182 | //! use domain::bits::DNameBuf; 183 | //! use domain::resolv::Resolver; 184 | //! use domain::resolv::lookup::lookup_host; 185 | //! 186 | //! fn main() { 187 | //! let response = Resolver::run(|resolv| { 188 | //! let name = DNameBuf::from_str("www.rust-lang.org").unwrap(); 189 | //! lookup_host(resolv, name) 190 | //! }); 191 | //! for addr in response.unwrap().iter() { 192 | //! println!("{}", addr); 193 | //! } 194 | //! } 195 | //! ``` 196 | //! 197 | //! 198 | //! [futures]: https://github.com/alexcrichton/futures-rs 199 | //! [tokio]: https://tokio.rs/ 200 | //! [intro]: intro/index.html 201 | //! [lookup]: lookup/index.html 202 | //! [`Error`]: error/enum.Error.html 203 | //! [`MessageBuf`]: ../bits/message/struct.MessageBuf.html 204 | //! [`ResolvConf`]: conf/struct.ResolvConf.html 205 | //! [`Resolver`]: struct.Resolver.html 206 | //! [`Resolver::start()`]: struct.Resolver.html#method.start 207 | //! [`Resolver::run()`]: struct.Resolver.html#method.run 208 | //! [`Resolver::query()`]: struct.Resolver.html#method.query 209 | //! [`lookup_addr()`]: lookup/fn.lookup_addr.html 210 | //! [`lookup_host()`]: lookup/fn.lookup_host.html 211 | 212 | 213 | //------------ Re-exports ---------------------------------------------------- 214 | 215 | pub use self::conf::ResolvConf; 216 | pub use self::public::{Query, Resolver}; 217 | 218 | 219 | //------------ Public Modules ------------------------------------------------ 220 | 221 | pub mod conf; 222 | pub mod error; 223 | pub mod lookup; 224 | 225 | 226 | //------------ Meta-modules for Documentation -------------------------------- 227 | 228 | pub mod intro; 229 | 230 | 231 | //------------ Private Modules ----------------------------------------------- 232 | 233 | mod channel; 234 | mod public; 235 | mod request; 236 | mod tcp; 237 | mod transport; 238 | mod udp; 239 | -------------------------------------------------------------------------------- /src/resolv/tcp.rs: -------------------------------------------------------------------------------- 1 | /// TCP channel and transport. 2 | 3 | use std::io; 4 | use std::net::SocketAddr; 5 | use futures::{Poll, StartSend}; 6 | use tokio_core::net::{TcpStream, TcpStreamNew}; 7 | use tokio_core::reactor; 8 | use ::bits::MessageBuf; 9 | use super::conf::ServerConf; 10 | use super::channel::{Channel, ConnectStream, StreamChannel}; 11 | use super::request::{TransportHandle, TransportRequest}; 12 | use super::transport::{TransportMode, spawn_transport}; 13 | 14 | 15 | //------------ tcp_transport ------------------------------------------------- 16 | 17 | /// Spawns a new TCP transport for the given server config into a reactor. 18 | /// 19 | /// Returns the transport handle for the TCP transport or `None` if TCP 20 | /// was disabled for this server. 21 | pub fn tcp_transport(reactor: &reactor::Handle, conf: &ServerConf) 22 | -> Option { 23 | let mode = match TransportMode::resolve(conf.tcp, 24 | Some(TransportMode::SingleRequest)) { 25 | Some(mode) => mode, 26 | None => return None, 27 | }; 28 | let channel = TcpChannel::new(conf.addr, reactor.clone()); 29 | Some(spawn_transport(reactor, channel, mode, conf)) 30 | } 31 | 32 | 33 | //------------ TcpChannel ---------------------------------------------------- 34 | 35 | /// A channel using TCP as the transport protocol. 36 | /// 37 | /// This is a simple wrapper around a `StreamChannel` using the `ConnectTCP` 38 | /// connector defined below. 39 | struct TcpChannel(StreamChannel); 40 | 41 | impl TcpChannel { 42 | /// Creates a new TCP channel using the given peer address and reactor. 43 | fn new(addr: SocketAddr, handle: reactor::Handle) -> Self { 44 | TcpChannel(StreamChannel::new(ConnectTcp{addr: addr, handle: handle})) 45 | } 46 | } 47 | 48 | 49 | //--- Channel 50 | 51 | impl Channel for TcpChannel { 52 | fn start_send(&mut self, request: TransportRequest) 53 | -> StartSend { 54 | self.0.start_send(request) 55 | } 56 | 57 | fn poll_send(&mut self) -> Poll, io::Error> { 58 | self.0.poll_send() 59 | } 60 | 61 | fn poll_recv(&mut self) -> Poll { 62 | self.0.poll_recv() 63 | } 64 | 65 | fn sleep(&mut self) -> Result<(), io::Error> { 66 | self.0.sleep() 67 | } 68 | } 69 | 70 | 71 | //------------ ConnectTcp ---------------------------------------------------- 72 | 73 | /// A connector for a TCP peer. 74 | struct ConnectTcp { 75 | /// The address of the peer. 76 | addr: SocketAddr, 77 | 78 | /// A reactor handle for starting the connecting process on. 79 | handle: reactor::Handle, 80 | } 81 | 82 | 83 | //--- ConnectStream 84 | 85 | impl ConnectStream for ConnectTcp { 86 | type Stream = TcpStream; 87 | type Future = TcpStreamNew; 88 | 89 | fn connect(&self) -> Self::Future { 90 | TcpStream::connect(&self.addr, &self.handle) 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/resolv/transport/mod.rs: -------------------------------------------------------------------------------- 1 | /// DNS Transports. 2 | /// 3 | /// While the actual sending and receiving of messages is done 4 | /// implementations of the `Channel` trait, there needs to be some logic 5 | /// governing in which order multiple parallel requests are sent to a server. 6 | /// This is what transports do. 7 | /// 8 | /// There are (at least) three ways how servers expect their requests: The 9 | /// most obvious one is *multiplexed,* that is, we send all requests right 10 | /// away, each with a different ID, and then match received responses using 11 | /// their ID. Alternatively, we can operate *sequentially* by sending a 12 | /// request and waiting for its response before sending a new request. 13 | /// Finally, in *single request* mode each request is sent, its response 14 | /// received and then the socket is closed. 15 | /// 16 | /// Consequently, this module contains three different transport 17 | /// implementations in the `multiplex`, `sequential`, and `single` submodules. 18 | /// 19 | /// Towards the outside world, only the `spawn_transport()` function is 20 | /// really relevant which spawns a transport into a reactor core. Which 21 | /// particular strategy the transport will be using is defined by the 22 | /// `TransportMode` enum 23 | 24 | pub use self::spawn::{TransportMode, spawn_transport}; 25 | 26 | mod multiplex; 27 | mod pending; 28 | mod sequential; 29 | mod single; 30 | mod spawn; 31 | 32 | -------------------------------------------------------------------------------- /src/resolv/transport/multiplex.rs: -------------------------------------------------------------------------------- 1 | //! A transport that multiplexes requests. 2 | 3 | use std::io; 4 | use std::time::Duration; 5 | use futures::{Async, AsyncSink, Future, Poll, Stream}; 6 | use tokio_core::reactor; 7 | use super::super::channel::Channel; 8 | use super::super::conf::ServerConf; 9 | use super::super::request::{RequestReceiver, TransportRequest}; 10 | use super::pending::PendingRequests; 11 | 12 | 13 | //------------ Transport ----------------------------------------------------- 14 | 15 | /// A transport that multiplexes requests over a single socket. 16 | /// 17 | /// The transport will send out all requests received immediately and then 18 | /// keep them in a map. Whenever it receives a response, it tries to find 19 | /// the matching request and resolve it. 20 | /// 21 | /// Requests for which there are no responses received within the time 22 | /// given by the config’s request timeout are being failed with a timeout 23 | /// error. 24 | /// 25 | /// The transport will use the configuration’s keep alive duration as an 26 | /// indicator for how long to keep a channel active when there are no new 27 | /// requests. 28 | pub struct Transport { 29 | /// The receiver for new requests. 30 | /// 31 | /// This gets switched to `None` when the receiver gets disconnected or 32 | /// taken away by the expiring wrapper. If that has happened, we wait 33 | /// until all pending request have expired and then end the stream. 34 | receiver: Option, 35 | 36 | /// The underlying channel. 37 | channel: C, 38 | 39 | /// The duration before we send the channel to sleep. 40 | keep_alive: Duration, 41 | 42 | /// A map with all the requests currently in flight. 43 | pending: PendingRequests, 44 | 45 | /// A timeout that is started whenever we run out of requests. 46 | /// 47 | /// When it fires, we send the channel to sleep. 48 | sleep_timeout: Option, 49 | 50 | /// A request that is waiting to be sent. 51 | send_request: Option, 52 | } 53 | 54 | 55 | impl Transport { 56 | /// Creates a new multiplexing transport. 57 | pub fn new(receiver: RequestReceiver, channel: C, 58 | reactor: reactor::Handle, conf: &ServerConf) -> Self { 59 | Transport { 60 | receiver: Some(receiver), 61 | channel: channel, 62 | keep_alive: conf.keep_alive, 63 | pending: PendingRequests::new(reactor, conf.request_timeout), 64 | sleep_timeout: None, 65 | send_request: None, 66 | } 67 | } 68 | } 69 | 70 | impl Transport { 71 | /// Spawns a new multiplxing transport into a reactor. 72 | pub fn spawn(receiver: RequestReceiver, channel: C, 73 | reactor: &reactor::Handle, conf: &ServerConf) { 74 | let transport = Self::new(receiver, channel, reactor.clone(), conf); 75 | reactor.spawn(transport); 76 | } 77 | } 78 | 79 | 80 | //--- Future 81 | 82 | impl Future for Transport { 83 | type Item = (); 84 | type Error = (); 85 | 86 | fn poll(&mut self) -> Poll<(), ()> { 87 | match self.poll_step() { 88 | Ok(()) => Ok(Async::NotReady), 89 | Err(_) => { 90 | self.pending.fail_all(); 91 | self.receiver = None; 92 | Ok(Async::Ready(())) 93 | } 94 | } 95 | } 96 | } 97 | 98 | impl Transport { 99 | /// Does everything necessary for a single poll. 100 | /// 101 | /// If this returns `Ok(())`, then polling is done and 102 | /// `Ok(Async::NotReady)` should be returned by the `poll()` method. 103 | /// 104 | /// Any errors happening are passed straight through and need to be 105 | /// sorted out by the `poll()` method. 106 | fn poll_step(&mut self) -> io::Result<()> { 107 | self.poll_sleep()?; 108 | self.poll_recv()?; 109 | self.poll_send()?; 110 | self.pending.expire(); 111 | self.set_sleep_timeout()?; 112 | Ok(()) 113 | } 114 | 115 | /// Reads and processes responses until reading blocks. 116 | fn poll_recv(&mut self) -> io::Result<()> { 117 | while let Async::Ready(response) = self.channel.poll_recv()? { 118 | let id = response.header().id(); 119 | if let Some(request) = self.pending.pop(id) { 120 | request.response(response); 121 | } 122 | } 123 | Ok(()) 124 | } 125 | 126 | /// Sends out requests until either writing blocks or there are no more. 127 | fn poll_send(&mut self) -> io::Result<()> { 128 | loop { 129 | match self.channel.poll_send()? { 130 | Async::NotReady => return Ok(()), 131 | Async::Ready(None) => { } 132 | Async::Ready(Some(request)) => { 133 | self.pending.push(request) 134 | } 135 | } 136 | self.get_send_request()?; 137 | if self.send_request.is_none() { 138 | return Ok(()) 139 | } 140 | self.start_send()?; 141 | } 142 | } 143 | 144 | /// Attempts to provide a send request. 145 | /// 146 | /// If available, a request is placed in `self.send_request`. If there 147 | /// is no requests at this time, `self.send_request` is left at `None`- 148 | fn get_send_request(&mut self) -> io::Result<()> { 149 | if self.send_request.is_some() { 150 | return Ok(()) 151 | } 152 | match self.receiver { 153 | None => return Ok(()), 154 | Some(ref mut receiver) => { 155 | match receiver.poll() { 156 | Ok(Async::NotReady) => return Ok(()), 157 | Ok(Async::Ready(Some(request))) => { 158 | self.send_request = self.pending 159 | .prepare_request(request); 160 | self.sleep_timeout = None; 161 | return Ok(()) 162 | } 163 | Ok(Async::Ready(None)) | Err(_) => { 164 | // Fall through to drop the receiver. 165 | } 166 | } 167 | } 168 | } 169 | self.receiver = None; 170 | Ok(()) 171 | } 172 | 173 | /// Attempts to start sending a request. 174 | fn start_send(&mut self) -> io::Result<()> { 175 | let request = match self.send_request.take() { 176 | None => return Ok(()), 177 | Some(request) => request 178 | }; 179 | if let AsyncSink::NotReady(request) 180 | = self.channel.start_send(request)? { 181 | self.send_request = Some(request) 182 | } 183 | Ok(()) 184 | } 185 | 186 | /// Checks if the sleep timeout expired and sends the channel to sleep. 187 | fn poll_sleep(&mut self) -> io::Result<()> { 188 | match self.sleep_timeout { 189 | None => return Ok(()), 190 | Some(ref mut timeout) => { 191 | if let Async::NotReady = timeout.poll()? { 192 | return Ok(()) 193 | } 194 | } 195 | } 196 | self.channel.sleep()?; 197 | self.sleep_timeout = None; 198 | Ok(()) 199 | } 200 | 201 | /// Sets the sleep timer if necessary. 202 | fn set_sleep_timeout(&mut self) -> io::Result<()> { 203 | if self.sleep_timeout.is_none() && self.pending.is_empty() { 204 | self.sleep_timeout 205 | = Some(reactor::Timeout::new(self.keep_alive, 206 | self.pending.reactor())?); 207 | } 208 | Ok(()) 209 | } 210 | } 211 | 212 | -------------------------------------------------------------------------------- /src/resolv/transport/pending.rs: -------------------------------------------------------------------------------- 1 | //! `PendingRequests`, a collection of pending requests. 2 | //! 3 | //! This is used by `multiplex::Transport` to store all the pending requests. 4 | 5 | use std::io; 6 | use std::collections::{HashMap, VecDeque}; 7 | use std::time::{Duration, Instant}; 8 | use futures::{Async, Future}; 9 | use rand::random; 10 | use tokio_core::reactor; 11 | use super::super::error::Error; 12 | use super::super::request::TransportRequest; 13 | 14 | 15 | 16 | //------------ PendingRequests ----------------------------------------------- 17 | 18 | /// A collection of pending requests. 19 | pub struct PendingRequests { 20 | /// A map from DNS message IDs to requests. 21 | /// 22 | /// If an ID is reserved, it maps to `None`, if a request has been 23 | /// pushed for it, it maps to `Some(_)`. 24 | requests: HashMap>, 25 | 26 | /// An ordered list of message IDs and when they expire. 27 | /// 28 | /// Since we have a fixed duration and monotone time, we can use a 29 | /// simple deque here and push new requests to its end. 30 | expires: VecDeque<(u16, Instant)>, 31 | 32 | /// The optional future for the next time a request expires. 33 | timeout: Option, 34 | 35 | /// A handle to a reactor for creating timeout futures. 36 | reactor: reactor::Handle, 37 | 38 | /// The duration until a request expires. 39 | duration: Duration, 40 | } 41 | 42 | impl PendingRequests { 43 | /// Creates a new collection. 44 | pub fn new(reactor: reactor::Handle, expire: Duration) -> Self { 45 | PendingRequests { 46 | requests: HashMap::new(), 47 | expires: VecDeque::new(), 48 | timeout: None, 49 | reactor: reactor, 50 | duration: expire 51 | } 52 | } 53 | 54 | /// Returns a reference to the value’s reactor handle. 55 | pub fn reactor(&self) -> &reactor::Handle { 56 | &self.reactor 57 | } 58 | 59 | /// Returns whether there are no more pending requests. 60 | /// 61 | /// This will also account for reserved requests. 62 | pub fn is_empty(&self) -> bool { 63 | self.requests.is_empty() 64 | } 65 | 66 | /// Prepares a request for later insertion. 67 | /// 68 | /// Returns the prepared request on success. If preparing fails, then 69 | /// the request is failed and `None` is returned. 70 | pub fn prepare_request(&mut self, mut request: TransportRequest) 71 | -> Option { 72 | match self.reserve() { 73 | Ok(id) => { 74 | request.set_id(id); 75 | Some(request) 76 | } 77 | Err(_) => { 78 | request.fail(io::Error::new(io::ErrorKind::Other, 79 | "too many requests").into()); 80 | None 81 | } 82 | } 83 | } 84 | 85 | /// Reserves a spot in the map and returns its ID. 86 | pub fn reserve(&mut self) -> Result { 87 | use std::collections::hash_map::Entry; 88 | 89 | // Pick a reasonably low number here so that we won’t hang too long 90 | // below. 91 | if self.requests.len() > 0xA000 { 92 | return Err(ReserveError); 93 | } 94 | // XXX I suppose there is a better way to do this. Anyone? 95 | loop { 96 | let id = random(); 97 | if let Entry::Vacant(entry) = self.requests.entry(id) { 98 | entry.insert(None); 99 | return Ok(id) 100 | } 101 | } 102 | } 103 | 104 | /// Adds the requests with the given ID to the collection. 105 | /// 106 | /// The `id` must have been reserved before and nothing been pushed 107 | /// for this ID since. Panics otherwise. 108 | pub fn push(&mut self, request: TransportRequest) { 109 | let id = request.id().unwrap(); 110 | { 111 | let entry = self.requests.get_mut(&id) 112 | .expect("pushed unreserved ID"); 113 | if entry.is_some() { 114 | panic!("pushed over existing ID"); 115 | } 116 | *entry = Some(request); 117 | } 118 | self.expires.push_back((id, Instant::now() + self.duration)); 119 | if self.timeout.is_none() { 120 | self.update_timeout(); 121 | } 122 | } 123 | 124 | /// Removes and returns the request with the given ID. 125 | pub fn pop(&mut self, id: u16) -> Option { 126 | if let Some(request) = self.requests.remove(&id) { 127 | if self.expires.front().unwrap().0 == id { 128 | self.expires.pop_front(); 129 | self.update_timeout(); 130 | } 131 | request 132 | } 133 | else { None } 134 | } 135 | 136 | /// Updates the timeout. 137 | /// 138 | /// Since we don’t delete the IDs in `pop()` (which could be expensive 139 | /// if they are somewhere in the middle), we need to pop items from the 140 | /// front until we find one that is actually still valid. 141 | fn update_timeout(&mut self) { 142 | while let Some(&(id, at)) = self.expires.front() { 143 | if self.requests.contains_key(&id) { 144 | // XXX What’s the best thing to do when getting a timeout 145 | // fails? 146 | self.timeout = reactor::Timeout::new_at(at, 147 | &self.reactor).ok(); 148 | return; 149 | } 150 | else { 151 | self.expires.pop_front(); 152 | } 153 | } 154 | self.timeout = None 155 | } 156 | 157 | /// Removes and fails all expired requests. 158 | /// 159 | /// This method polls `self`’s timeout so it can only be called from 160 | /// within a task. 161 | pub fn expire(&mut self) { 162 | match self.timeout { 163 | Some(ref mut timeout) => { 164 | match timeout.poll() { 165 | Ok(Async::NotReady) => return, 166 | Ok(Async::Ready(())) => { 167 | loop { 168 | match self.expires.front() { 169 | Some(&(_, at)) if at < Instant::now() => { } 170 | _ => break 171 | } 172 | let id = self.expires.pop_front().unwrap().0; 173 | if let Some(Some(item)) = self.requests 174 | .remove(&id) { 175 | item.timeout() 176 | } 177 | } 178 | } 179 | Err(_) => { 180 | // Fall through to update_timeout to perhaps fix 181 | // the broken timeout. 182 | } 183 | } 184 | } 185 | None => return 186 | } 187 | self.update_timeout(); 188 | // Once more to register the timeout. 189 | self.expire() 190 | } 191 | 192 | /// Fails all pending requests. 193 | pub fn fail_all(&mut self) { 194 | for (_, item) in self.requests.drain() { 195 | if let Some(item) = item { 196 | item.fail(Error::Timeout) 197 | } 198 | } 199 | } 200 | } 201 | 202 | 203 | //--- Drop 204 | 205 | impl Drop for PendingRequests { 206 | fn drop(&mut self) { 207 | self.fail_all() 208 | } 209 | } 210 | 211 | 212 | //------------ ReserveError -------------------------------------------------- 213 | 214 | /// An error happened while reserving an ID. 215 | /// 216 | /// The only thing that can happen is that we run out of space. 217 | pub struct ReserveError; 218 | 219 | -------------------------------------------------------------------------------- /src/resolv/transport/sequential.rs: -------------------------------------------------------------------------------- 1 | //! A transport that sends requests sequentially. 2 | 3 | use std::io; 4 | use std::time::Duration; 5 | use rand::random; 6 | use futures::{Async, AsyncSink, Future, Poll, Stream}; 7 | use tokio_core::reactor; 8 | use super::super::channel::Channel; 9 | use super::super::conf::ServerConf; 10 | use super::super::request::{RequestReceiver, TransportRequest}; 11 | 12 | 13 | //------------ Transport ----------------------------------------------------- 14 | 15 | /// A transport that sends requests sequentially. 16 | /// 17 | /// The transport will send one request, wait for its response, discarding any 18 | /// other responses, resolve the request, and only then move on to the next 19 | /// requests. 20 | /// 21 | /// A request will time out if a response isn’t received within the time 22 | /// given by the config’s request timeout. If no new request is received 23 | /// for the time given by the config’s keep alive duration, the underlying 24 | /// channel will be sent to sleep. 25 | pub struct Transport { 26 | /// The request receiver. 27 | receiver: RequestReceiver, 28 | 29 | /// The underlying channel. 30 | channel: C, 31 | 32 | /// The duration before a request expires. 33 | request_timeout: Duration, 34 | 35 | /// The duration before we send the channel to sleep. 36 | keep_alive: Duration, 37 | 38 | /// A reactor handle for creating timeouts futures. 39 | reactor: reactor::Handle, 40 | 41 | /// The current operational state. 42 | state: State, 43 | 44 | /// The request we are currently processing. 45 | /// 46 | /// Whether there is one depends on the state. Not having this be part 47 | /// of the respective variants of the `State` enum safes us having to 48 | /// temporarily `mem::replace()` the state all the time at the price of 49 | /// possible inconsistencies and, therefore, panics. 50 | request: Option 51 | } 52 | 53 | /// The state of processing. 54 | enum State { 55 | /// We are waiting for a request. 56 | Idle, 57 | 58 | /// We received a request and now need to start sending it. 59 | /// 60 | /// In this state, `self.request´ must contain a request. 61 | Starting, 62 | 63 | /// We have successfully started to send a request and now need for it 64 | /// to finish sending. 65 | Sending, 66 | 67 | /// We have sent the request and are now waiting for the response to 68 | /// arrive. If no response has been received when the timeout fires, 69 | /// we need to timeout the request. 70 | /// 71 | /// In this state, `self.request´ must contain a request. 72 | Receiving(reactor::Timeout), 73 | 74 | /// We are done processing a request. The channel is still active while 75 | /// we are waiting for a new request to arrive. If the timeout fires, 76 | /// we can send the channel to sleep and proceed to idle state. 77 | Doze(reactor::Timeout), 78 | 79 | /// This transport is done and must not be polled anymore on penalty of 80 | /// a panic. 81 | Closed, 82 | } 83 | 84 | impl Transport { 85 | /// Creates a new sequential transport. 86 | pub fn new(receiver: RequestReceiver, channel: C, 87 | reactor: reactor::Handle, conf: &ServerConf) -> Self { 88 | Transport { 89 | receiver: receiver, 90 | channel: channel, 91 | request_timeout: conf.request_timeout, 92 | keep_alive: conf.keep_alive, 93 | reactor: reactor, 94 | state: State::Idle, 95 | request: None, 96 | } 97 | } 98 | } 99 | 100 | impl Transport { 101 | /// Spawns a new sequential transport into a reactor core. 102 | pub fn spawn(receiver: RequestReceiver, channel: C, 103 | reactor: &reactor::Handle, conf: &ServerConf) { 104 | let transport = Self::new(receiver, channel, reactor.clone(), conf); 105 | reactor.spawn(transport); 106 | } 107 | } 108 | 109 | 110 | //--- Future 111 | 112 | impl Future for Transport { 113 | type Item = (); 114 | type Error = (); 115 | 116 | fn poll(&mut self) -> Poll<(), ()> { 117 | loop { 118 | match self.poll_step() { 119 | Ok(Async::Ready(State::Closed)) => { 120 | assert!(self.request.is_none()); 121 | self.state = State::Closed; 122 | return Ok(Async::Ready(())) 123 | } 124 | Ok(Async::Ready(state)) => self.state = state, 125 | Ok(Async::NotReady) => return Ok(Async::NotReady), 126 | Err(err) => { 127 | if let Some(request) = self.request.take() { 128 | request.fail(err.into()) 129 | } 130 | self.state = State::Closed; 131 | return Ok(Async::Ready(())); 132 | } 133 | } 134 | } 135 | } 136 | } 137 | 138 | impl Transport { 139 | /// A single poll step and return the new state. 140 | /// 141 | /// This method can be called repeatedly, replacing the state with the 142 | /// returned state until it returns `Ok(Async::NotReady)` at which time 143 | /// the loop should end. 144 | fn poll_step(&mut self) -> Poll { 145 | // Check for timeouts first because this mutably references `self` 146 | // prohibiting calling `&mut self` methods. 147 | if let State::Receiving(ref mut timeout) = self.state { 148 | if let Async::Ready(()) = timeout.poll()? { 149 | let request = self.request.take().unwrap(); 150 | request.timeout(); 151 | let timeout = reactor::Timeout::new(self.keep_alive, 152 | &self.reactor)?; 153 | return Ok(Async::Ready(State::Doze(timeout))); 154 | } 155 | } 156 | if let State::Doze(ref mut timeout) = self.state { 157 | if let Async::Ready(()) = timeout.poll()? { 158 | self.channel.sleep()?; 159 | return Ok(Async::Ready(State::Idle)); 160 | } 161 | } 162 | match self.state { 163 | State::Idle | State::Doze(_) => self.poll_idle(), 164 | State::Starting => self.poll_starting(), 165 | State::Sending => self.poll_sending(), 166 | State::Receiving(_) => self.poll_receiving(), 167 | State::Closed => panic!("polling a closed transport"), 168 | } 169 | } 170 | 171 | /// Poll in idle state. 172 | /// 173 | /// Checks if the receiver has a new message for us. Returns starting 174 | /// state if it does, not ready if it doesn’t and the closing state if 175 | /// the receiver has been closed. 176 | fn poll_idle(&mut self) -> Poll { 177 | match self.receiver.poll().unwrap() { 178 | Async::NotReady => Ok(Async::NotReady), 179 | Async::Ready(None) => Ok(Async::Ready(State::Closed)), 180 | Async::Ready(Some(request)) => { 181 | self.request = Some(request); 182 | Ok(Async::Ready(State::Starting)) 183 | } 184 | } 185 | } 186 | 187 | /// Polls in starting state. 188 | /// 189 | /// Tries to give the request to the channel for sending. This should 190 | /// normally always succeed unless there is a logic error somewhere. 191 | /// Returns sending state if it did indeed succeed and starting state 192 | /// if not. 193 | fn poll_starting(&mut self) -> Poll { 194 | let mut request = self.request.take().unwrap(); 195 | request.set_id(random()); 196 | match self.channel.start_send(request)? { 197 | AsyncSink::Ready => Ok(Async::Ready(State::Sending)), 198 | AsyncSink::NotReady(request) => { 199 | self.request = Some(request); 200 | Ok(Async::Ready(State::Starting)) 201 | } 202 | } 203 | } 204 | 205 | /// Polls in sending state. 206 | /// 207 | /// Polls the channel for sending, returning sending state until it gets 208 | /// the request back, proceeding to receiving state. 209 | fn poll_sending(&mut self) -> Poll { 210 | self.request = try_ready!(self.channel.poll_send()); 211 | assert!(self.request.is_some()); 212 | let timeout = reactor::Timeout::new(self.request_timeout, 213 | &self.reactor)?; 214 | Ok(Async::Ready(State::Receiving(timeout))) 215 | } 216 | 217 | /// Polls in receiving state. 218 | /// 219 | /// Polls the channel for receiving, checking every response whether it 220 | /// is for the request and, if so, resolving the request and proceeding 221 | /// to dozing state. Does not check the timeout for borrow checking 222 | /// reasons. 223 | fn poll_receiving(&mut self) -> Poll { 224 | let response = try_ready!(self.channel.poll_recv()); 225 | if self.request.as_ref().unwrap().id().unwrap() 226 | != response.header().id() { 227 | return Ok(Async::NotReady); 228 | } 229 | let request = self.request.take().unwrap(); 230 | request.response(response); 231 | let timeout = reactor::Timeout::new(self.keep_alive, &self.reactor)?; 232 | Ok(Async::Ready(State::Doze(timeout))) 233 | } 234 | } 235 | 236 | -------------------------------------------------------------------------------- /src/resolv/transport/single.rs: -------------------------------------------------------------------------------- 1 | //! A transport that sends requests sequentially, sleeping between requests. 2 | use std::io; 3 | use std::time::Duration; 4 | use rand::random; 5 | use futures::{Async, AsyncSink, Future, Poll, Stream}; 6 | use tokio_core::reactor; 7 | use super::super::channel::Channel; 8 | use super::super::conf::ServerConf; 9 | use super::super::request::{RequestReceiver, TransportRequest}; 10 | 11 | 12 | //------------ Transport ----------------------------------------------------- 13 | 14 | /// A transport that sends requests sequentially, sleeping between requests. 15 | /// 16 | /// The transport will send one request, wait for its response, discarding any 17 | /// other responses, resolve the request, send the channel to sleep 18 | /// thereby causing it to close the socket, and then wait for the next 19 | /// request. 20 | /// 21 | /// A request will time out if a response isn’t received within the time 22 | /// given by the config’s request timeout. If no new request is received 23 | /// for the time given by the config’s keep alive duration, the underlying 24 | /// channel will be sent to sleep. 25 | pub struct Transport { 26 | /// The request receiver. 27 | receiver: RequestReceiver, 28 | 29 | /// The underlying channel. 30 | channel: C, 31 | 32 | /// The duration before a request expires. 33 | request_timeout: Duration, 34 | 35 | /// A reactor handle for creating timeouts futures. 36 | reactor: reactor::Handle, 37 | 38 | /// The current operational state. 39 | state: State, 40 | 41 | /// The request we are currently processing. 42 | /// 43 | /// Whether there is one depends on the state. Not having this be part 44 | /// of the respective variants of the `State` enum safes us having to 45 | /// temporarily `mem::replace()` the state all the time at the price of 46 | /// possible inconsistencies and, therefore, panics. 47 | request: Option 48 | } 49 | 50 | enum State { 51 | /// Waiting for a new request to arrive. 52 | Idle, 53 | 54 | /// A request is ready to be enqueued with the channel. 55 | /// 56 | /// In this state, `self.request´ must contain a request. 57 | Starting, 58 | 59 | /// The channel is currently sending the request. 60 | Sending, 61 | 62 | /// Waiting to receive a response from the channel. 63 | /// 64 | /// The included timer is started with the request timeout once the 65 | /// request has been sent. 66 | /// 67 | /// In this state, `self.request´ must contain a request. 68 | Receiving(reactor::Timeout), 69 | 70 | /// The receiver has closed down or the channel errored out. 71 | Closed, 72 | } 73 | 74 | impl Transport { 75 | /// Creates a new single-request transport. 76 | pub fn new(receiver: RequestReceiver, channel: C, 77 | reactor: reactor::Handle, conf: &ServerConf) -> Self { 78 | Transport { 79 | receiver: receiver, 80 | channel: channel, 81 | request_timeout: conf.request_timeout, 82 | reactor: reactor, 83 | state: State::Idle, 84 | request: None, 85 | } 86 | } 87 | } 88 | 89 | impl Transport { 90 | /// Spawns a new single-request transport into a reactor core. 91 | pub fn spawn(receiver: RequestReceiver, channel: C, 92 | reactor: &reactor::Handle, conf: &ServerConf) { 93 | let transport = Self::new(receiver, channel, reactor.clone(), conf); 94 | reactor.spawn(transport); 95 | } 96 | } 97 | 98 | 99 | //--- Future 100 | 101 | impl Future for Transport { 102 | type Item = (); 103 | type Error = (); 104 | 105 | fn poll(&mut self) -> Poll<(), ()> { 106 | loop { 107 | match self.poll_step() { 108 | Ok(Async::Ready(State::Closed)) => { 109 | assert!(self.request.is_none()); 110 | self.state = State::Closed; 111 | return Ok(Async::Ready(())) 112 | } 113 | Ok(Async::Ready(state)) => self.state = state, 114 | Ok(Async::NotReady) => return Ok(Async::NotReady), 115 | Err(err) => { 116 | if let Some(request) = self.request.take() { 117 | request.fail(err.into()) 118 | } 119 | self.state = State::Closed; 120 | return Ok(Async::Ready(())); 121 | } 122 | } 123 | } 124 | } 125 | } 126 | 127 | impl Transport { 128 | /// A single poll step and return the new state. 129 | /// 130 | /// This method can be called repeatedly, replacing the state with the 131 | /// returned state until it returns `Ok(Async::NotReady)` at which time 132 | /// the loop should end. 133 | fn poll_step(&mut self) -> Poll { 134 | // Check for timeout first because this mutably references `self` 135 | // prohibiting calling `&mut self` methods. 136 | if let State::Receiving(ref mut timeout) = self.state { 137 | if let Async::Ready(()) = timeout.poll()? { 138 | let request = self.request.take().unwrap(); 139 | request.timeout(); 140 | return Ok(Async::Ready(State::Idle)); 141 | } 142 | } 143 | match self.state { 144 | State::Idle => self.poll_idle(), 145 | State::Starting => self.poll_starting(), 146 | State::Sending => self.poll_sending(), 147 | State::Receiving(_) => self.poll_receiving(), 148 | State::Closed => panic!("polling a closed transport"), 149 | } 150 | } 151 | 152 | /// Polls in idle state. 153 | /// 154 | /// Checks if the receiver has a new message for us. Returns starting 155 | /// state if it does, not ready if it doesn’t and the closing state if 156 | /// the receiver has been closed. 157 | fn poll_idle(&mut self) -> Poll { 158 | match self.receiver.poll().unwrap() { 159 | Async::NotReady => Ok(Async::NotReady), 160 | Async::Ready(None) => Ok(Async::Ready(State::Closed)), 161 | Async::Ready(Some(request)) => { 162 | self.request = Some(request); 163 | Ok(Async::Ready(State::Starting)) 164 | } 165 | } 166 | } 167 | 168 | /// Polls in starting state. 169 | /// 170 | /// Tries to give the request to the channel for sending. This should 171 | /// normally always succeed unless there is a logic error somewhere. 172 | /// Returns sending state if it did indeed succeed and starting state 173 | /// if not. 174 | fn poll_starting(&mut self) -> Poll { 175 | let mut request = self.request.take().unwrap(); 176 | request.set_id(random()); 177 | match self.channel.start_send(request)? { 178 | AsyncSink::Ready => Ok(Async::Ready(State::Sending)), 179 | AsyncSink::NotReady(request) => { 180 | self.request = Some(request); 181 | Ok(Async::Ready(State::Starting)) 182 | } 183 | } 184 | } 185 | 186 | /// Polls in sending state. 187 | /// 188 | /// Polls the channel for sending, returning sending state until it gets 189 | /// the request back, proceeding to receiving state. 190 | fn poll_sending(&mut self) -> Poll { 191 | self.request = try_ready!(self.channel.poll_send()); 192 | assert!(self.request.is_some()); 193 | let timeout = reactor::Timeout::new(self.request_timeout, 194 | &self.reactor)?; 195 | Ok(Async::Ready(State::Receiving(timeout))) 196 | } 197 | 198 | /// Polls in receiving state. 199 | /// 200 | /// Polls the channel for receiving, checking every response whether it 201 | /// is for the request and, if so, resolving the request and proceeding 202 | /// to idle state. 203 | fn poll_receiving(&mut self) -> Poll { 204 | let response = try_ready!(self.channel.poll_recv()); 205 | if self.request.as_ref().unwrap().id().unwrap() 206 | != response.header().id() { 207 | return Ok(Async::NotReady); 208 | } 209 | let request = self.request.take().unwrap(); 210 | request.response(response); 211 | self.channel.sleep()?; 212 | Ok(Async::Ready(State::Idle)) 213 | } 214 | } 215 | 216 | -------------------------------------------------------------------------------- /src/resolv/transport/spawn.rs: -------------------------------------------------------------------------------- 1 | //! The `spawn_transport()` function for starting transport and what it needs. 2 | 3 | use tokio_core::reactor; 4 | use super::super::channel::Channel; 5 | use super::super::conf::ServerConf; 6 | use super::super::request::TransportHandle; 7 | use super::super::conf::ServerMode; 8 | use super::{single, sequential, multiplex}; 9 | 10 | 11 | //------------ spawn_transport ----------------------------------------------- 12 | 13 | /// Spawns a new transport and returns a handle to it. 14 | /// 15 | /// The transport will be spawned into `reactor` which will also be used by 16 | /// both the transport and the underlying channel given by `channel`. The 17 | /// strategy for dispatching messages is given through `mode`. Any additional 18 | /// information that the transport may need is taken from `conf`. 19 | /// 20 | /// The function returns a transport handle for dispatching requests to the 21 | /// newly spawned transport. 22 | pub fn spawn_transport(reactor: &reactor::Handle, channel: C, 23 | mode: TransportMode, conf: &ServerConf) 24 | -> TransportHandle 25 | where C : Channel + 'static { 26 | let (tx, rx) = TransportHandle::channel(); 27 | match mode { 28 | TransportMode::SingleRequest 29 | => single::Transport::spawn(rx, channel, reactor, conf), 30 | TransportMode::Sequential 31 | => sequential::Transport::spawn(rx, channel, reactor, conf), 32 | TransportMode::Multiplex 33 | => multiplex::Transport::spawn(rx, channel, reactor, conf) 34 | } 35 | tx 36 | } 37 | 38 | 39 | //------------ TransportMode ------------------------------------------------- 40 | 41 | /// The mode a transport will operate in. 42 | /// 43 | /// This is essientally `conf::ServerMode` stripped off the the variants that 44 | /// a real transport can’t have. 45 | #[derive(Clone, Copy, Debug)] 46 | pub enum TransportMode { 47 | SingleRequest, 48 | Sequential, 49 | Multiplex, 50 | } 51 | 52 | impl TransportMode { 53 | /// Returns the `TransportMode` for a given `ServerMode`. 54 | /// 55 | /// Since `ServerMode` has both a `None` and a `Default` variant, 56 | /// this function takes the service mode to use by default and returns 57 | /// an option for the `None` case. 58 | pub fn resolve(mode: ServerMode, default: Option) -> Option { 59 | match mode { 60 | ServerMode::None => None, 61 | ServerMode::Default => default, 62 | ServerMode::SingleRequest => Some(TransportMode::SingleRequest), 63 | ServerMode::Sequential => Some(TransportMode::Sequential), 64 | ServerMode::Multiplex => Some(TransportMode::Multiplex) 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/resolv/udp.rs: -------------------------------------------------------------------------------- 1 | /// UDP channel and transport. 2 | 3 | use std::io; 4 | use std::net::{IpAddr, SocketAddr}; 5 | use futures::{Async, AsyncSink, Poll, StartSend}; 6 | use tokio_core::net::UdpSocket; 7 | use tokio_core::reactor; 8 | use ::bits::MessageBuf; 9 | use super::conf::ServerConf; 10 | use super::request::{TransportHandle, TransportRequest}; 11 | use super::channel::Channel; 12 | use super::transport::{TransportMode, spawn_transport}; 13 | 14 | 15 | //------------ udp_transport ------------------------------------------------- 16 | 17 | /// Spawns a new TCP transport for the given server config into a reactor. 18 | /// 19 | /// Returns the transport handle for the TCP transport or `None` if TCP 20 | /// was disabled for this server. 21 | pub fn udp_transport(reactor: &reactor::Handle, conf: &ServerConf) 22 | -> Option { 23 | let mode = match TransportMode::resolve(conf.udp, 24 | Some(TransportMode::Multiplex)) { 25 | Some(mode) => mode, 26 | None => return None, 27 | }; 28 | let channel = UdpChannel::new(conf.addr, reactor.clone(), conf.recv_size); 29 | Some(spawn_transport(reactor, channel, mode, conf)) 30 | } 31 | 32 | 33 | //------------ UdpChannel ---------------------------------------------------- 34 | 35 | /// A channel using UDP as the transport protocol. 36 | /// 37 | /// Note that `tokio_core` currently does not support connecting UDP sockets 38 | /// so we have to do some filtering on our side. This should probably be 39 | /// fixed. 40 | struct UdpChannel { 41 | /// The address of the peer. 42 | peer: SocketAddr, 43 | 44 | /// A handle to reactor core to use for creating sockets. 45 | handle: reactor::Handle, 46 | 47 | /// The maximum size of an incoming message. 48 | recv_size: usize, 49 | 50 | /// The socket if we currently have one. 51 | sock: Option, 52 | 53 | /// The transport request we are currently trying to send, if any. 54 | wr: Option, 55 | } 56 | 57 | impl UdpChannel { 58 | /// Creates a new UDP channel. 59 | fn new(peer: SocketAddr, handle: reactor::Handle, recv_size: usize) 60 | -> Self { 61 | UdpChannel { 62 | peer: peer, 63 | handle: handle, 64 | recv_size: recv_size, 65 | sock: None, 66 | wr: None, 67 | } 68 | } 69 | } 70 | 71 | 72 | //--- Channel 73 | 74 | impl Channel for UdpChannel { 75 | fn start_send(&mut self, request: TransportRequest) 76 | -> StartSend { 77 | if self.wr.is_some() { 78 | return Ok(AsyncSink::NotReady(request)) 79 | } 80 | self.wr = Some(request); 81 | if self.sock.is_none() { 82 | let local = match self.peer { 83 | SocketAddr::V4(_) 84 | => SocketAddr::new(IpAddr::V4(0.into()), 0), 85 | SocketAddr::V6(_) 86 | => SocketAddr::new(IpAddr::V6([0;16].into()), 0) 87 | }; 88 | self.sock = Some(UdpSocket::bind(&local, &self.handle)?); 89 | } 90 | Ok(AsyncSink::Ready) 91 | } 92 | 93 | fn poll_send(&mut self) -> Poll, io::Error> { 94 | { 95 | let sock = match self.sock { 96 | Some(ref mut sock) => sock, 97 | None => return Ok(Async::Ready(None)), 98 | }; 99 | let wr = match self.wr { 100 | Some(ref mut wr) => wr, 101 | None => return Ok(Async::Ready(None)), 102 | }; 103 | let mut msg = wr.message(); 104 | let buf = msg.dgram_bytes(); 105 | let size = try_nb!(sock.send_to(buf, &self.peer)); 106 | if size != buf.len() { 107 | // XXX Is this too drastic? 108 | return Err(io::Error::new(io::ErrorKind::Other, "short write")) 109 | } 110 | } 111 | Ok(Async::Ready(self.wr.take())) 112 | } 113 | 114 | fn poll_recv(&mut self) -> Poll { 115 | let sock = match self.sock { 116 | Some(ref mut sock) => sock, 117 | None => return Ok(Async::NotReady) 118 | }; 119 | loop { 120 | if let Async::NotReady = sock.poll_read() { 121 | return Ok(Async::NotReady) 122 | } 123 | let mut buf = vec![0u8; self.recv_size]; 124 | let (size, addr) = try_nb!(sock.recv_from(&mut buf)); 125 | if addr != self.peer { 126 | continue 127 | } 128 | buf.resize(size, 0); 129 | if let Ok(msg) = MessageBuf::from_vec(buf) { 130 | return Ok(Async::Ready(msg)) 131 | } 132 | } 133 | } 134 | 135 | fn sleep(&mut self) -> Result<(), io::Error> { 136 | self.sock = None; 137 | self.wr = None; 138 | Ok(()) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | //! Various utility modules. 2 | //! 3 | //! This should probably be separate crates … 4 | 5 | pub mod netdb; 6 | -------------------------------------------------------------------------------- /src/utils/netdb.rs: -------------------------------------------------------------------------------- 1 | //! The network database. 2 | //! 3 | //! This module provides a placeholder implementation for some of the 4 | //! functions included in POSIX’s (?) network database. 5 | //! 6 | //! For the moment, implementations here are functional in the sense that 7 | //! they simulate an empty database. Since we are only using this for 8 | //! parsing WKS records for the moment, this seems to be a reasonably 9 | //! shortcut. 10 | //! 11 | //! Furthermore, if this gets implemented for real, it should be considered 12 | //! whether giving out clones of the entities is really necessary. 13 | 14 | 15 | //------------ ProtoEnt ----------------------------------------------------- 16 | 17 | pub struct ProtoEnt { 18 | pub name: String, 19 | pub aliases: Vec, 20 | pub proto: u8, 21 | } 22 | 23 | impl ProtoEnt { 24 | pub fn by_name(name: &str) -> Option { 25 | let _ = name; 26 | None 27 | } 28 | 29 | pub fn by_number(number: u8) -> Option { 30 | let _ = number; 31 | None 32 | } 33 | 34 | pub fn iter() -> ProtoIter { 35 | ProtoIter 36 | } 37 | } 38 | 39 | 40 | //------------ ProtoIter ---------------------------------------------------- 41 | 42 | pub struct ProtoIter; 43 | 44 | impl Iterator for ProtoIter { 45 | type Item = ProtoEnt; 46 | 47 | fn next(&mut self) -> Option { 48 | None 49 | } 50 | } 51 | 52 | 53 | //------------ ServEnt ------------------------------------------------------ 54 | 55 | pub struct ServEnt { 56 | pub name: String, 57 | pub aliases: Vec, 58 | pub port: u16, 59 | pub proto: String 60 | } 61 | 62 | impl ServEnt { 63 | pub fn by_name(name: &str) -> Option { 64 | let _ = name; 65 | None 66 | } 67 | 68 | pub fn by_port(port: u16) -> Option { 69 | let _ = port; 70 | None 71 | } 72 | 73 | pub fn iter() -> ServIter { 74 | ServIter 75 | } 76 | } 77 | 78 | 79 | //------------ ServIter ------------------------------------------------------ 80 | 81 | pub struct ServIter; 82 | 83 | impl Iterator for ServIter { 84 | type Item = ServEnt; 85 | 86 | fn next(&mut self) -> Option { 87 | None 88 | } 89 | } 90 | 91 | --------------------------------------------------------------------------------