├── .clippy.toml ├── .github ├── actions-rs │ └── grcov.yml └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── message.rs ├── examples ├── decode.rs ├── ecs_decode.rs ├── ecs_encode.rs └── encode.rs ├── fuzz ├── .gitignore ├── Cargo.toml └── src │ └── decode_encode_decode.rs ├── src ├── decode │ ├── decoder.rs │ ├── dns.rs │ ├── domain_name.rs │ ├── error.rs │ ├── helpers.rs │ ├── macros.rs │ ├── mod.rs │ ├── question.rs │ ├── rr │ │ ├── draft_ietf_dnsop_svcb_https.rs │ │ ├── edns │ │ │ ├── mod.rs │ │ │ ├── rfc_6891.rs │ │ │ ├── rfc_7830.rs │ │ │ ├── rfc_7871.rs │ │ │ └── rfc_7873.rs │ │ ├── enums.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── rfc_1035.rs │ │ ├── rfc_1183.rs │ │ ├── rfc_1706.rs │ │ ├── rfc_1712.rs │ │ ├── rfc_1876.rs │ │ ├── rfc_2163.rs │ │ ├── rfc_2230.rs │ │ ├── rfc_2782.rs │ │ ├── rfc_3123.rs │ │ ├── rfc_3596.rs │ │ ├── rfc_3658.rs │ │ ├── rfc_4034.rs │ │ ├── rfc_6672.rs │ │ ├── rfc_6742.rs │ │ ├── rfc_7043.rs │ │ ├── rfc_7553.rs │ │ ├── rfc_8659.rs │ │ ├── subtypes.rs │ │ ├── tests.rs │ │ └── unknown.rs │ └── tests.rs ├── dns.rs ├── domain_name.rs ├── encode │ ├── dns.rs │ ├── domain_name.rs │ ├── encoder.rs │ ├── error.rs │ ├── helpers.rs │ ├── macros.rs │ ├── mod.rs │ ├── question.rs │ ├── rr │ │ ├── draft_ietf_dnsop_svcb_https.rs │ │ ├── edns │ │ │ ├── mod.rs │ │ │ ├── rfc_6891.rs │ │ │ ├── rfc_7830.rs │ │ │ ├── rfc_7871.rs │ │ │ └── rfc_7873.rs │ │ ├── enums.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── rfc_1035.rs │ │ ├── rfc_1183.rs │ │ ├── rfc_1706.rs │ │ ├── rfc_1712.rs │ │ ├── rfc_1876.rs │ │ ├── rfc_2163.rs │ │ ├── rfc_2230.rs │ │ ├── rfc_2782.rs │ │ ├── rfc_3123.rs │ │ ├── rfc_3596.rs │ │ ├── rfc_3658.rs │ │ ├── rfc_4034.rs │ │ ├── rfc_6672.rs │ │ ├── rfc_6742.rs │ │ ├── rfc_7043.rs │ │ ├── rfc_7553.rs │ │ ├── rfc_8659.rs │ │ ├── subtypes.rs │ │ ├── tests.rs │ │ └── unknown.rs │ └── tests.rs ├── label.rs ├── lib.rs ├── macros.rs ├── question.rs ├── rr │ ├── draft_ietf_dnsop_svcb_https.rs │ ├── edns │ │ ├── mod.rs │ │ ├── rfc_6891.rs │ │ ├── rfc_7830.rs │ │ ├── rfc_7871.rs │ │ └── rfc_7873.rs │ ├── enums.rs │ ├── macros.rs │ ├── mod.rs │ ├── rfc_1035.rs │ ├── rfc_1183.rs │ ├── rfc_1706.rs │ ├── rfc_1712.rs │ ├── rfc_1876.rs │ ├── rfc_2163.rs │ ├── rfc_2230.rs │ ├── rfc_2782.rs │ ├── rfc_3123.rs │ ├── rfc_3596.rs │ ├── rfc_3658.rs │ ├── rfc_4034.rs │ ├── rfc_6672.rs │ ├── rfc_6742.rs │ ├── rfc_7043.rs │ ├── rfc_7553.rs │ ├── rfc_8659.rs │ ├── subtypes.rs │ ├── tests.rs │ └── unknown.rs └── subtypes.rs └── tests ├── class.rs ├── decode.rs ├── decode_encode_decode.rs ├── decode_error.rs ├── display.rs ├── domain_name.rs ├── error.rs ├── generic.rs ├── question.rs └── ttl.rs /.clippy.toml: -------------------------------------------------------------------------------- 1 | cognitive-complexity-threshold = 15 2 | too-many-arguments-threshold = 10 3 | single-char-binding-names-threshold = 8 4 | -------------------------------------------------------------------------------- /.github/actions-rs/grcov.yml: -------------------------------------------------------------------------------- 1 | branch: false 2 | ignore-not-existing: true 3 | llvm: true 4 | output-type: lcov 5 | output-path: lcov.info 6 | ignore: 7 | - "tests/*" 8 | - "examples/*" 9 | - "/*" 10 | excl-line: "#\\[" 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | rustfmt: 14 | name: Job rustfmt 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Install toolchain with rustfmt 18 | uses: dtolnay/rust-toolchain@stable 19 | with: 20 | components: rustfmt 21 | - uses: actions/checkout@v4 22 | - name: Run rustfmt 23 | run: cargo fmt --all -- --check 24 | 25 | clippy: 26 | name: Job clippy 27 | needs: rustfmt 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Install toolchain with clippy 31 | uses: dtolnay/rust-toolchain@stable 32 | with: 33 | components: clippy 34 | - uses: actions/checkout@v4 35 | - name: Run clippy 36 | uses: giraffate/clippy-action@v1 37 | with: 38 | reporter: 'github-pr-check' 39 | github_token: ${{ secrets.GITHUB_TOKEN }} 40 | clippy_flags: --deny warnings -A clippy::unknown-clippy-lints 41 | 42 | tests: 43 | name: Job tests 44 | needs: clippy 45 | strategy: 46 | matrix: 47 | os: [ubuntu-latest, macos-latest, windows-latest] 48 | rust_channel: [stable, nightly] 49 | runs-on: ${{ matrix.os }} 50 | steps: 51 | - name: Install toolchain ${{ matrix.rust_channel }} on ${{ matrix.os }} 52 | uses: dtolnay/rust-toolchain@master 53 | with: 54 | toolchain: ${{ matrix.rust_channel }} 55 | - uses: actions/checkout@v4 56 | - name: Run cargo test 57 | run: cargo test --no-default-features --features "${{ matrix.features }}" 58 | 59 | code-coverage: 60 | name: Job code coverage 61 | needs: tests 62 | runs-on: ubuntu-latest 63 | steps: 64 | - name: Intall toolchain nightly on ubuntu-latest 65 | uses: dtolnay/rust-toolchain@stable 66 | with: 67 | components: llvm-tools-preview 68 | - uses: actions/checkout@v4 69 | - name: cargo install cargo-llvm-cov 70 | uses: taiki-e/install-action@cargo-llvm-cov 71 | - name: cargo llvm-cov 72 | run: cargo llvm-cov --all-features --lcov --output-path lcov.info 73 | - name: Upload to codecov.io 74 | uses: codecov/codecov-action@v4 75 | with: 76 | token: ${{ secrets.CODECOV_TOKEN }} 77 | env_vars: OS,RUST 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dns-message-parser" 3 | version = "0.8.0" 4 | authors = ["LinkTed "] 5 | edition = "2018" 6 | readme = "README.md" 7 | keywords = ["dns", "parser", "encode", "decode"] 8 | description = "Libary to encode and decode DNS packets" 9 | license = "BSD-3-Clause" 10 | repository = "https://github.com/LinkTed/dns-message-parser" 11 | include = [ 12 | "src/**/*.rs", 13 | "tests/*.rs", 14 | "examples/*.rs", 15 | "Cargo.toml", 16 | "README.md", 17 | "LICENSE", 18 | ] 19 | categories = [ 20 | "parser-implementations", 21 | "encoding" 22 | ] 23 | 24 | [dependencies] 25 | base64 = "0.22" 26 | bytes = "1" 27 | hex = "0.4" 28 | thiserror = "2" 29 | 30 | [dev-dependencies] 31 | criterion = "0.5" 32 | 33 | [[bench]] 34 | name = "message" 35 | path = "benches/message.rs" 36 | harness = false 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, LinkTed 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dns-message-parser 2 | A library to encode and decode DNS packets ([RFC1035](https://tools.ietf.org/html/rfc1035), [RFC2535](https://tools.ietf.org/html/rfc2535)). 3 | 4 | [![Build status](https://github.com/LinkTed/dns-message-parser/workflows/Continuous%20Integration/badge.svg)](https://github.com/LinkTed/dns-message-parser/actions?query=workflow%3A%22Continuous+Integration%22) 5 | [![Dependency status](https://deps.rs/repo/github/linkted/dns-message-parser/status.svg)](https://deps.rs/repo/github/linkted/dns-message-parser) 6 | [![Code coverage](https://codecov.io/gh/LinkTed/dns-message-parser/branch/master/graph/badge.svg)](https://codecov.io/gh/LinkTed/dns-message-parser) 7 | [![Latest version](https://img.shields.io/crates/v/dns-message-parser.svg)](https://crates.io/crates/dns-message-parser) 8 | [![License](https://img.shields.io/crates/l/dns-message-parser.svg)](https://opensource.org/licenses/BSD-3-Clause) 9 | 10 | **This library is not completed yet.** 11 | 12 | ## Usage 13 | Add this to your `Cargo.toml`: 14 | ```toml 15 | [dependencies] 16 | dns-message-parser = "0.7.0" 17 | ``` 18 | 19 | ## Example 20 | ```rust 21 | use bytes::Bytes; 22 | use dns_message_parser::{Dns, DomainName, Flags, Opcode, RCode}; 23 | use dns_message_parser::question::{QClass, QType, Question}; 24 | 25 | fn decode_example() { 26 | let msg = b"\xdb\x1c\x85\x80\x00\x01\x00\x01\x00\x00\x00\x00\x07\x65\x78\x61\x6d\x70\x6c\x65\ 27 | \x03\x6f\x72\x67\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\x0a\x00\ 28 | \x00\x0a"; 29 | 30 | let bytes = Bytes::copy_from_slice(&msg[..]); 31 | 32 | let dns = Dns::decode(bytes).unwrap(); 33 | println!("{:?}", dns); 34 | } 35 | 36 | fn encode_example() { 37 | let id = 56092; 38 | let flags = Flags { 39 | qr: true, 40 | opcode: Opcode::Query, 41 | aa: true, 42 | tc: false, 43 | rd: true, 44 | ra: true, 45 | ad: false, 46 | cd: false, 47 | rcode: RCode::NoError, 48 | }; 49 | let question = { 50 | let domain_name = "example.org.".parse().unwrap(); 51 | let q_class = QClass::IN; 52 | let q_type = QType::A; 53 | 54 | Question { 55 | domain_name, 56 | q_class, 57 | q_type, 58 | } 59 | }; 60 | 61 | let questions = vec![question]; 62 | let dns = Dns { 63 | id, 64 | flags, 65 | questions, 66 | answers: Vec::new(), 67 | authorities: Vec::new(), 68 | additionals: Vec::new(), 69 | }; 70 | let bytes = dns.encode().unwrap(); 71 | println!("{:?}", bytes); 72 | } 73 | ``` 74 | -------------------------------------------------------------------------------- /benches/message.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; 3 | use dns_message_parser::Dns; 4 | use std::time::Duration; 5 | 6 | static A: &[u8; 45] = 7 | b"\xdb\x1c\x85\x80\x00\x01\x00\x01\x00\x00\x00\x00\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x6f\x72\ 8 | \x67\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\x0a\x00\x00\x0a"; 9 | 10 | static NS: &[u8; 97] = 11 | b"\x03\x78\x85\x80\x00\x01\x00\x02\x00\x00\x00\x02\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x6f\x72\ 12 | \x67\x00\x00\x02\x00\x01\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x06\x03\x6e\x73\x31\xc0\ 13 | \x0c\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x06\x03\x6e\x73\x32\xc0\x0c\xc0\x29\x00\x01\ 14 | \x00\x01\x00\x00\x0e\x10\x00\x04\x7f\x00\x00\x01\xc0\x3b\x00\x01\x00\x01\x00\x00\x0e\x10\x00\ 15 | \x04\x0a\x00\x00\x01"; 16 | 17 | static CNAME: &[u8; 49] = 18 | b"\xe2\x7b\x85\x80\x00\x01\x00\x01\x00\x00\x00\x00\x05\x63\x6e\x61\x6d\x65\x07\x65\x78\x61\x6d\ 19 | \x70\x6c\x65\x03\x6f\x72\x67\x00\x00\x05\x00\x01\xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\x00\ 20 | \x02\xc0\x12"; 21 | 22 | static SOA: &[u8; 75] = 23 | b"\xeb\x9c\x85\x80\x00\x01\x00\x01\x00\x00\x00\x00\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x6f\x72\ 24 | \x67\x00\x00\x06\x00\x01\xc0\x0c\x00\x06\x00\x01\x00\x00\x0e\x10\x00\x22\x03\x6e\x73\x31\xc0\ 25 | \x0c\x05\x61\x64\x6d\x69\x6e\xc0\x0c\x00\x00\x00\x01\x00\x00\x2a\x30\x00\x00\x0e\x10\x00\x09\ 26 | \x3a\x80\x00\x00\x0e\x10"; 27 | 28 | static PTR: &[u8; 64] = 29 | b"\x0c\x72\x85\x80\x00\x01\x00\x01\x00\x00\x00\x00\x02\x31\x30\x01\x30\x01\x30\x02\x31\x30\x07\ 30 | \x65\x78\x61\x6d\x70\x6c\x65\x03\x6f\x72\x67\x00\x00\x0c\x00\x01\xc0\x0c\x00\x0c\x00\x01\x00\ 31 | \x00\x0e\x10\x00\x0d\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x6f\x72\x67\x00"; 32 | 33 | static MESSAGES: [(&[u8], &str); 5] = [ 34 | (A, "a"), 35 | (NS, "NS"), 36 | (CNAME, "CNAME"), 37 | (SOA, "SOA"), 38 | (PTR, "PTR"), 39 | ]; 40 | 41 | fn decode(c: &mut Criterion) { 42 | let mut group = c.benchmark_group("decode"); 43 | for (dns, name) in MESSAGES.iter() { 44 | let dns = Bytes::from_static(dns); 45 | let name = name.to_owned(); 46 | let throughput = Throughput::Bytes(dns.len() as u64); 47 | let benchmark_id = BenchmarkId::new(name, dns.len()); 48 | group.throughput(throughput); 49 | group.bench_with_input(benchmark_id, &dns, |b, dns| { 50 | b.iter(|| Dns::decode(dns.clone()).unwrap()) 51 | }); 52 | } 53 | group.finish(); 54 | } 55 | 56 | fn encode(c: &mut Criterion) { 57 | let mut group = c.benchmark_group("encode"); 58 | for (dns, name) in MESSAGES.iter() { 59 | let dns = Bytes::from_static(dns); 60 | let dns = Dns::decode(dns).unwrap(); 61 | let bytes = dns.encode().unwrap(); 62 | let name = name.to_owned(); 63 | let throughput = Throughput::Bytes(bytes.len() as u64); 64 | let benchmark_id = BenchmarkId::new(name, bytes.len()); 65 | group.throughput(throughput); 66 | group.bench_with_input(benchmark_id, &dns, |b, dns| { 67 | b.iter(|| dns.encode().unwrap()) 68 | }); 69 | } 70 | group.finish(); 71 | } 72 | 73 | criterion_group! { 74 | name = benches; 75 | config = Criterion::default() 76 | .sample_size(1024) 77 | .measurement_time(Duration::from_secs(10)); 78 | targets = decode, encode 79 | } 80 | criterion_main!(benches); 81 | -------------------------------------------------------------------------------- /examples/decode.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use dns_message_parser::Dns; 3 | 4 | fn main() { 5 | let msg = b"\xdb\x1c\x85\x80\x00\x01\x00\x01\x00\x00\x00\x00\x07\x65\x78\x61\x6d\x70\x6c\x65\ 6 | \x03\x6f\x72\x67\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\x0a\x00\ 7 | \x00\x0a"; 8 | 9 | let bytes = Bytes::copy_from_slice(&msg[..]); 10 | 11 | let dns = Dns::decode(bytes).unwrap(); 12 | println!("{:?}", dns); 13 | } 14 | -------------------------------------------------------------------------------- /examples/ecs_decode.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use dns_message_parser::Dns; 3 | 4 | fn main() { 5 | let msg = b"\x7d\x2a\x85\x80\x00\x01\x00\x01\x00\x00\x00\x01\x07\x65\x78\x61\x6d\x70\x6c\x65\ 6 | \x03\x6f\x72\x67\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\x0a\x00\ 7 | \x00\x0a\x00\x00\x29\x04\xd0\x00\x00\x00\x00\x00\x10\x00\x08\x00\x0c\x00\x02\x40\x00\x00\x00\ 8 | \x00\x00\x00\x00\x00\x00"; 9 | 10 | let bytes = Bytes::copy_from_slice(&msg[..]); 11 | // Decode the DNS message 12 | let dns = Dns::decode(bytes).unwrap(); 13 | println!("{:?}", dns); 14 | } 15 | -------------------------------------------------------------------------------- /examples/ecs_encode.rs: -------------------------------------------------------------------------------- 1 | use dns_message_parser::{ 2 | question::{QClass, QType, Question}, 3 | rr::edns::{EDNSOption, ECS}, 4 | rr::{Address, A, OPT, RR}, 5 | {Dns, Flags, Opcode, RCode}, 6 | }; 7 | 8 | fn main() { 9 | let id = 32042; 10 | let flags = Flags { 11 | qr: true, 12 | opcode: Opcode::Query, 13 | aa: true, 14 | tc: false, 15 | rd: true, 16 | ra: true, 17 | ad: false, 18 | cd: false, 19 | rcode: RCode::NoError, 20 | }; 21 | 22 | let q_a = { 23 | let domain_name = "example.org.".parse().unwrap(); 24 | let q_class = QClass::IN; 25 | let q_type = QType::A; 26 | 27 | Question { 28 | domain_name, 29 | q_class, 30 | q_type, 31 | } 32 | }; 33 | let questions = vec![q_a]; 34 | 35 | let rr_a = { 36 | let domain_name = "example.org.".parse().unwrap(); 37 | let ttl = 3600; 38 | let ipv4_addr = "10.0.0.10".parse().unwrap(); 39 | let a = A { 40 | domain_name, 41 | ttl, 42 | ipv4_addr, 43 | }; 44 | RR::A(a) 45 | }; 46 | let answers = vec![rr_a]; 47 | 48 | // Create the EDNS structs 49 | let rr_opt = { 50 | let requestor_payload_size = 1232; 51 | let extend_rcode = 0; 52 | let version = 0; 53 | let dnssec = false; 54 | // Create EDNS Client Subnet 55 | let edns_ecs = { 56 | let address = Address::Ipv4("10.0.0.0".parse().unwrap()); 57 | // source_prefix_length = 12 58 | // scope_prefix_length = 24 59 | // adress = 127.0.0.1 60 | let ecs = ECS::new(12, 24, address).unwrap(); 61 | EDNSOption::ECS(ecs) 62 | }; 63 | let edns_options = vec![edns_ecs]; 64 | let opt = OPT { 65 | requestor_payload_size, 66 | extend_rcode, 67 | version, 68 | dnssec, 69 | edns_options, 70 | }; 71 | RR::OPT(opt) 72 | }; 73 | let additionals = vec![rr_opt]; 74 | 75 | let dns = Dns { 76 | id, 77 | flags, 78 | questions, 79 | answers, 80 | authorities: Vec::new(), 81 | additionals, 82 | }; 83 | 84 | let bytes = dns.encode().unwrap(); 85 | println!("{:x}", bytes); 86 | } 87 | -------------------------------------------------------------------------------- /examples/encode.rs: -------------------------------------------------------------------------------- 1 | use dns_message_parser::{ 2 | question::{QClass, QType, Question}, 3 | {Dns, Flags, Opcode, RCode}, 4 | }; 5 | 6 | fn main() { 7 | let id = 56092; 8 | let flags = Flags { 9 | qr: true, 10 | opcode: Opcode::Query, 11 | aa: true, 12 | tc: false, 13 | rd: true, 14 | ra: true, 15 | ad: false, 16 | cd: false, 17 | rcode: RCode::NoError, 18 | }; 19 | let question = { 20 | let domain_name = "example.org.".parse().unwrap(); 21 | let q_class = QClass::IN; 22 | let q_type = QType::A; 23 | 24 | Question { 25 | domain_name, 26 | q_class, 27 | q_type, 28 | } 29 | }; 30 | 31 | let questions = vec![question]; 32 | let dns = Dns { 33 | id, 34 | flags, 35 | questions, 36 | answers: Vec::new(), 37 | authorities: Vec::new(), 38 | additionals: Vec::new(), 39 | }; 40 | let bytes = dns.encode().unwrap(); 41 | println!("{:?}", bytes); 42 | } 43 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | hfuzz_target 2 | hfuzz_workspace 3 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz" 3 | version = "0.1.0" 4 | authors = ["LinkTed "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | honggfuzz = "~0.5.54" 9 | bytes = "~1.1.0" 10 | 11 | [dependencies.dns-message-parser] 12 | path = ".." 13 | 14 | [[bin]] 15 | name = "decode_encode_decode" 16 | path = "src/decode_encode_decode.rs" 17 | test = false 18 | doc = false 19 | -------------------------------------------------------------------------------- /fuzz/src/decode_encode_decode.rs: -------------------------------------------------------------------------------- 1 | use bytes::Bytes; 2 | use dns_message_parser::Dns; 3 | use honggfuzz::fuzz; 4 | 5 | #[inline(always)] 6 | fn decode_encode_decode(data: &[u8]) { 7 | let bytes = Bytes::copy_from_slice(data); 8 | if let Ok(dns_1) = Dns::decode(bytes) { 9 | match dns_1.encode() { 10 | Ok(bytes) => match Dns::decode(bytes.freeze()) { 11 | Ok(dns_2) => { 12 | if dns_1 != dns_2 { 13 | panic!( 14 | "Packet is not equal: {:?} != {:?}: {:?}", 15 | dns_1, dns_2, data 16 | ); 17 | } 18 | } 19 | Err(e) => { 20 | panic!( 21 | "Could not decode DNS packet: {:?}: {:?}: {:?}", 22 | e, data, dns_1 23 | ); 24 | } 25 | }, 26 | Err(e) => { 27 | panic!( 28 | "Could not encode DNS packet: {:?}: {:?}: {:?}", 29 | e, data, dns_1 30 | ); 31 | } 32 | } 33 | } 34 | } 35 | 36 | fn main() { 37 | loop { 38 | fuzz!(|data: &[u8]| { decode_encode_decode(data) }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/decode/decoder.rs: -------------------------------------------------------------------------------- 1 | use crate::{DecodeError, DecodeResult}; 2 | use bytes::Bytes; 3 | use std::cmp::Ordering; 4 | 5 | pub(crate) struct Decoder<'a, 'b: 'a> { 6 | pub parent: Option<&'a Decoder<'b, 'b>>, 7 | pub(super) bytes: Bytes, 8 | pub(super) offset: usize, 9 | } 10 | 11 | impl<'a, 'b: 'a> Decoder<'b, 'b> { 12 | pub(super) fn sub(&'a mut self, sub_length: u16) -> DecodeResult> { 13 | let bytes = self.read(sub_length as usize)?; 14 | let decoder = Decoder::<'a, 'b> { 15 | parent: Some(self), 16 | bytes, 17 | offset: 0, 18 | }; 19 | Ok(decoder) 20 | } 21 | } 22 | 23 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 24 | pub(crate) const fn main(bytes: Bytes) -> Decoder<'static, 'static> { 25 | Decoder { 26 | parent: None, 27 | bytes, 28 | offset: 0, 29 | } 30 | } 31 | 32 | pub(super) fn new_main_offset(&self, offset: usize) -> Decoder<'static, 'static> { 33 | let main = self.get_main(); 34 | Decoder { 35 | parent: None, 36 | bytes: main.bytes.clone(), 37 | offset, 38 | } 39 | } 40 | 41 | pub(super) const fn get_main(&self) -> &Decoder<'a, 'b> { 42 | let mut root = self; 43 | loop { 44 | match root.parent { 45 | Some(parent) => root = parent, 46 | None => return root, 47 | } 48 | } 49 | } 50 | 51 | pub(super) fn is_finished(&self) -> DecodeResult { 52 | let bytes_len = self.bytes.len(); 53 | match self.offset.cmp(&bytes_len) { 54 | Ordering::Less => Ok(false), 55 | Ordering::Equal => Ok(true), 56 | Ordering::Greater => Err(DecodeError::NotEnoughBytes(bytes_len, self.offset)), 57 | } 58 | } 59 | 60 | pub(super) fn finished(self) -> DecodeResult<()> { 61 | match self.is_finished()? { 62 | true => Ok(()), 63 | false => Err(DecodeError::TooManyBytes(self.bytes.len(), self.offset)), 64 | } 65 | } 66 | 67 | pub(super) fn read(&mut self, length: usize) -> DecodeResult { 68 | let start = self.offset; 69 | self.offset += length; 70 | if self.offset <= self.bytes.len() { 71 | Ok(self.bytes.slice(start..self.offset)) 72 | } else { 73 | Err(DecodeError::NotEnoughBytes(self.bytes.len(), self.offset)) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/decode/dns.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::{DecodeError, DecodeResult, Dns, Flags, Opcode, RCode, MAXIMUM_DNS_PACKET_SIZE}; 3 | use std::convert::TryFrom; 4 | 5 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 6 | fn flags(&mut self) -> DecodeResult { 7 | let buffer = self.u8()?; 8 | let qr = (buffer & 0b1000_0000) != 0; 9 | let opcode = (buffer & 0b0111_1000) >> 3; 10 | let opcode = match Opcode::try_from(opcode) { 11 | Ok(opcode) => opcode, 12 | Err(buffer) => return Err(DecodeError::Opcode(buffer)), 13 | }; 14 | let aa = (buffer & 0b0000_0100) != 0; 15 | let tc = (buffer & 0b0000_0010) != 0; 16 | let rd = (buffer & 0b0000_0001) != 0; 17 | let buffer = self.u8()?; 18 | let ra = (buffer & 0b1000_0000) != 0; 19 | let z = buffer & 0b0100_0000; 20 | if z != 0 { 21 | return Err(DecodeError::ZNotZeroes(z)); 22 | } 23 | let ad = (buffer & 0b0010_0000) != 0; 24 | let cd = (buffer & 0b0001_0000) != 0; 25 | let rcode = buffer & 0b0000_1111; 26 | match RCode::try_from(rcode) { 27 | Ok(rcode) => Ok(Flags { 28 | qr, 29 | opcode, 30 | aa, 31 | tc, 32 | rd, 33 | ra, 34 | ad, 35 | cd, 36 | rcode, 37 | }), 38 | Err(buffer) => Err(DecodeError::RCode(buffer)), 39 | } 40 | } 41 | } 42 | 43 | impl<'a, 'b: 'a> Decoder<'b, 'b> { 44 | fn dns(&'a mut self) -> DecodeResult { 45 | if self.offset != 0 { 46 | return Err(DecodeError::Offset(self.offset)); 47 | } 48 | 49 | let bytes_len = self.bytes.len(); 50 | if bytes_len < 12 { 51 | return Err(DecodeError::NotEnoughBytes(bytes_len, 12)); 52 | } else if bytes_len > MAXIMUM_DNS_PACKET_SIZE { 53 | return Err(DecodeError::DnsPacketTooBig(bytes_len)); 54 | } 55 | 56 | let id = self.u16()?; 57 | let flags = self.flags()?; 58 | let question_count = self.u16()?; 59 | let answer_count = self.u16()?; 60 | let authority_count = self.u16()?; 61 | let additional_count = self.u16()?; 62 | 63 | let mut questions = Vec::with_capacity(question_count as usize); 64 | for _ in 0..question_count { 65 | questions.push(self.question()?); 66 | } 67 | let mut answers = Vec::with_capacity(answer_count as usize); 68 | for _ in 0..answer_count { 69 | answers.push(self.rr()?); 70 | } 71 | let mut authorities = Vec::with_capacity(authority_count as usize); 72 | for _ in 0..authority_count { 73 | authorities.push(self.rr()?); 74 | } 75 | let mut additionals = Vec::with_capacity(additional_count as usize); 76 | for _ in 0..additional_count { 77 | additionals.push(self.rr()?); 78 | } 79 | 80 | let is_finished = self.is_finished()?; 81 | let dns = Dns { 82 | id, 83 | flags, 84 | questions, 85 | answers, 86 | authorities, 87 | additionals, 88 | }; 89 | 90 | if is_finished { 91 | Ok(dns) 92 | } else { 93 | Err(DecodeError::RemainingBytes(self.offset, dns)) 94 | } 95 | } 96 | } 97 | 98 | impl_decode!(Flags, flags); 99 | 100 | impl_decode!(Dns, dns); 101 | -------------------------------------------------------------------------------- /src/decode/domain_name.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | decode::Decoder, domain_name::DOMAIN_NAME_MAX_RECURSION, DecodeError, DecodeResult, DomainName, 3 | }; 4 | use std::{collections::HashSet, str::from_utf8, usize}; 5 | 6 | const COMPRESSION_BITS: u8 = 0b1100_0000; 7 | const COMPRESSION_BITS_REV: u8 = 0b0011_1111; 8 | 9 | #[inline] 10 | const fn is_compressed(length: u8) -> bool { 11 | (length & COMPRESSION_BITS) == COMPRESSION_BITS 12 | } 13 | 14 | #[inline] 15 | const fn get_offset(length_1: u8, length_2: u8) -> usize { 16 | (((length_1 & COMPRESSION_BITS_REV) as usize) << 8) | length_2 as usize 17 | } 18 | 19 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 20 | pub(super) fn domain_name(&mut self) -> DecodeResult { 21 | let mut domain_name = DomainName::default(); 22 | 23 | let mut length = self.u8()?; 24 | while length != 0 { 25 | if is_compressed(length) { 26 | let mut recursions = HashSet::new(); 27 | self.domain_name_recursion(&mut domain_name, &mut recursions, length)?; 28 | return Ok(domain_name); 29 | } else { 30 | length = self.domain_name_label(&mut domain_name, length)?; 31 | } 32 | } 33 | Ok(domain_name) 34 | } 35 | 36 | fn domain_name_label(&mut self, domain_name: &mut DomainName, length: u8) -> DecodeResult { 37 | let buffer = self.read(length as usize)?; 38 | let label = from_utf8(buffer.as_ref())?; 39 | let label = label.parse()?; 40 | domain_name.append_label(label)?; 41 | self.u8() 42 | } 43 | 44 | fn domain_name_recursion( 45 | &mut self, 46 | domain_name: &mut DomainName, 47 | recursions: &mut HashSet, 48 | mut length: u8, 49 | ) -> DecodeResult<()> { 50 | let mut buffer = self.u8()?; 51 | let mut offset = get_offset(length, buffer); 52 | let mut decoder = self.new_main_offset(offset); 53 | 54 | length = decoder.u8()?; 55 | 56 | while length != 0 { 57 | if is_compressed(length) { 58 | buffer = decoder.u8()?; 59 | offset = get_offset(length, buffer); 60 | if recursions.insert(offset) { 61 | let recursions_len = recursions.len(); 62 | if recursions_len > DOMAIN_NAME_MAX_RECURSION { 63 | return Err(DecodeError::MaxRecursion(recursions_len)); 64 | } 65 | } else { 66 | return Err(DecodeError::EndlessRecursion(offset)); 67 | } 68 | decoder.offset = offset as usize; 69 | length = decoder.u8()?; 70 | } else { 71 | length = decoder.domain_name_label(domain_name, length)?; 72 | } 73 | } 74 | 75 | Ok(()) 76 | } 77 | } 78 | 79 | impl_decode!(DomainName, domain_name); 80 | -------------------------------------------------------------------------------- /src/decode/error.rs: -------------------------------------------------------------------------------- 1 | use crate::rr::edns::CookieError; 2 | use crate::rr::{AddressError, Class, ISDNError, PSDNAddressError, TagError, Type}; 3 | use crate::{Dns, DomainName, DomainNameError, LabelError}; 4 | use hex::FromHexError; 5 | use std::str::Utf8Error; 6 | use thiserror::Error; 7 | 8 | #[derive(Debug, PartialEq, Error)] 9 | pub enum DecodeError { 10 | #[error("Not enough bytes to decode: got {0} offset {1}")] 11 | NotEnoughBytes(usize, usize), 12 | #[error("Too many bytes to decode: got {0} parsed {1}")] 13 | TooManyBytes(usize, usize), 14 | #[error("DNS packet is too big: {0}")] 15 | DnsPacketTooBig(usize), 16 | #[error("Could not decode Opcode: {0}")] 17 | Opcode(u8), 18 | #[error("Z bit is not zero: {0}")] 19 | ZNotZeroes(u8), 20 | #[error("Could not decode RCode: {0}")] 21 | RCode(u8), 22 | #[error("Could not decode Type: {0}")] 23 | Type(u16), 24 | #[error("Could not decode Class: {0}")] 25 | Class(u16), 26 | #[error("Could not decode QType: {0}")] 27 | QType(u16), 28 | #[error("Could not decode QClass: {0}")] 29 | QClass(u16), 30 | #[error("Could not decode string as UTF-8: {0}")] 31 | Utf8Error(#[from] Utf8Error), 32 | #[error("Could not decode label: {0}")] 33 | LabelError(#[from] LabelError), 34 | #[error("Could not decode domain name: {0}")] 35 | DomainNameError(#[from] DomainNameError), 36 | #[error("Decode of type {0} is not yet implemented")] 37 | NotYetImplemented(Type), 38 | #[error("Could not decode hex string: {0}")] 39 | FromHexError(#[from] FromHexError), 40 | #[error("Offset is not zero: {0}")] 41 | Offset(usize), 42 | #[error("Class is not IN for A record: {0}")] 43 | AClass(Class), 44 | #[error("Class is not IN for WKS record: {0}")] 45 | WKSClass(Class), 46 | #[error("The RData of the TXT is empty")] 47 | TXTEmpty, 48 | #[error("Could not decode AFSDBSubtype: {0}")] 49 | AFSDBSubtype(u16), 50 | #[error("Could not decode PSDN address: {0}")] 51 | PSDNAddressError(#[from] PSDNAddressError), 52 | #[error("Could not decode ISDN: {0}")] 53 | ISDNError(#[from] ISDNError), 54 | #[error("Could not decode GPOS")] 55 | GPOS, 56 | #[error("Class is not IN for AAAA record: {0}")] 57 | AAAAClass(Class), 58 | #[error("Domain name is not root: {0}")] 59 | OPTDomainName(DomainName), 60 | #[error("OPT header bits is not zero: {0}")] 61 | OPTZero(u8), 62 | #[error("Could not decode ENDSOptionCode: {0}")] 63 | EDNSOptionCode(u16), 64 | #[error("Could not decode Address: {0}")] 65 | AddressError(#[from] AddressError), 66 | #[error("Class is not IN for APL record: {0}")] 67 | APLClass(Class), 68 | #[error("Could not decode Cookie: {0}")] 69 | CookieError(#[from] CookieError), 70 | #[error("Could not decode AddressNumber: {0}")] 71 | EcsAddressNumber(u16), 72 | #[error("The IPv4 Address is too big: {0}")] 73 | EcsTooBigIpv4Address(usize), 74 | #[error("The IPv6 Address is too big: {0}")] 75 | EcsTooBigIpv6Address(usize), 76 | #[error("The cookie length is not 8 or between 16 and 40 bytes: {0}")] 77 | CookieLength(usize), 78 | #[error("Could not decode SSHFPAlgorithm: {0}")] 79 | SSHFPAlgorithm(u8), 80 | #[error("Could not decode SSHFPType: {0}")] 81 | SSHFPType(u8), 82 | #[error("Could not decode AlgorithmType: {0}")] 83 | AlgorithmType(u8), 84 | #[error("Could not decode DigestType: {0}")] 85 | DigestType(u8), 86 | #[error("The undefined flags are not zero: {0}")] 87 | DNSKEYZeroFlags(u16), 88 | #[error("DNSKEY protocol is not equal 3: {0}")] 89 | DNSKEYProtocol(u8), 90 | #[error("Could not decode the domain name, the because maximum recursion is reached: {0}")] 91 | MaxRecursion(usize), 92 | #[error("Could not decode the domain name, because an endless recursion was detected: {0}")] 93 | EndlessRecursion(usize), 94 | #[error("The are remaining bytes, which was not parsed")] 95 | RemainingBytes(usize, Dns), 96 | #[error("Padding is not zero: {0}")] 97 | PaddingZero(u8), 98 | #[error("Padding length is too long for u16: {0}")] 99 | PaddingLength(usize), 100 | #[error("Could not decode Tag: {0}")] 101 | TagError(#[from] TagError), 102 | #[error("ECH length mismatch. Expected {0} got {1}")] 103 | ECHLengthMismatch(usize, usize), 104 | } 105 | -------------------------------------------------------------------------------- /src/decode/helpers.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::{DecodeError, DecodeResult}; 3 | use bytes::Buf; 4 | use bytes::Bytes; 5 | use std::mem::size_of; 6 | use std::net::{Ipv4Addr, Ipv6Addr}; 7 | use std::str::from_utf8; 8 | 9 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 10 | pub(super) fn u8(&mut self) -> DecodeResult { 11 | let buffer = self.read(size_of::())?; 12 | Ok(buffer[0]) 13 | } 14 | 15 | pub(super) fn u16(&mut self) -> DecodeResult { 16 | let mut buffer = self.read(size_of::())?; 17 | Ok(buffer.get_u16()) 18 | } 19 | 20 | pub(super) fn u32(&mut self) -> DecodeResult { 21 | let mut buffer = self.read(size_of::())?; 22 | Ok(buffer.get_u32()) 23 | } 24 | 25 | pub(super) fn u64(&mut self) -> DecodeResult { 26 | let mut buffer = self.read(size_of::())?; 27 | Ok(buffer.get_u64()) 28 | } 29 | 30 | pub(super) fn string(&mut self) -> DecodeResult { 31 | let length = self.u8()? as usize; 32 | let buffer = self.read(length)?; 33 | let string = from_utf8(buffer.as_ref())?; 34 | Ok(String::from(string)) 35 | } 36 | 37 | pub(super) fn ipv4_addr(&mut self) -> DecodeResult { 38 | let ipv4_addr = self.u32()?; 39 | let ipv4_addr = Ipv4Addr::from(ipv4_addr); 40 | Ok(ipv4_addr) 41 | } 42 | 43 | pub(super) fn ipv6_addr(&mut self) -> DecodeResult { 44 | let a = self.u16()?; 45 | let b = self.u16()?; 46 | let c = self.u16()?; 47 | let d = self.u16()?; 48 | let e = self.u16()?; 49 | let f = self.u16()?; 50 | let g = self.u16()?; 51 | let h = self.u16()?; 52 | 53 | Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h)) 54 | } 55 | 56 | pub(super) fn bytes(&mut self) -> DecodeResult { 57 | let bytes_len = self.bytes.len(); 58 | if self.offset < bytes_len { 59 | let start = self.offset; 60 | self.offset = bytes_len; 61 | let bytes = self.bytes.slice(start..self.offset); 62 | Ok(bytes) 63 | } else { 64 | Err(DecodeError::NotEnoughBytes(bytes_len, self.offset)) 65 | } 66 | } 67 | 68 | pub(super) fn vec(&mut self) -> DecodeResult> { 69 | let bytes = self.bytes()?; 70 | Ok(bytes.to_vec()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/decode/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_decode { 2 | ($i:path, $m:ident) => { 3 | impl $i { 4 | pub fn decode(bytes: bytes::Bytes) -> crate::DecodeResult<$i> { 5 | let mut decoder = crate::decode::Decoder::main(bytes); 6 | decoder.$m() 7 | } 8 | } 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /src/decode/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | mod decoder; 4 | mod dns; 5 | mod domain_name; 6 | mod error; 7 | mod helpers; 8 | mod question; 9 | mod rr; 10 | #[cfg(test)] 11 | mod tests; 12 | 13 | use decoder::Decoder; 14 | pub use error::DecodeError; 15 | 16 | pub type DecodeResult = std::result::Result; 17 | -------------------------------------------------------------------------------- /src/decode/question.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | decode::Decoder, 3 | question::{QClass, QType, Question}, 4 | {DecodeError, DecodeResult}, 5 | }; 6 | use std::convert::TryFrom; 7 | 8 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 9 | pub fn q_type(&mut self) -> DecodeResult { 10 | let buffer = self.u16()?; 11 | match QType::try_from(buffer) { 12 | Ok(q_type) => Ok(q_type), 13 | Err(buffer) => Err(DecodeError::QType(buffer)), 14 | } 15 | } 16 | 17 | pub fn q_class(&mut self) -> DecodeResult { 18 | let buffer = self.u16()?; 19 | match QClass::try_from(buffer) { 20 | Ok(q_class) => Ok(q_class), 21 | Err(buffer) => Err(DecodeError::QClass(buffer)), 22 | } 23 | } 24 | 25 | pub fn question(&mut self) -> DecodeResult { 26 | let domain_name = self.domain_name()?; 27 | let q_type = self.q_type()?; 28 | let q_class = self.q_class()?; 29 | 30 | Ok(Question { 31 | domain_name, 32 | q_class, 33 | q_type, 34 | }) 35 | } 36 | } 37 | 38 | impl_decode!(QType, q_type); 39 | 40 | impl_decode!(QClass, q_class); 41 | 42 | impl_decode!(Question, question); 43 | -------------------------------------------------------------------------------- /src/decode/rr/draft_ietf_dnsop_svcb_https.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::error::DecodeError::ECHLengthMismatch; 2 | use crate::decode::Decoder; 3 | use crate::rr::{ServiceBinding, ServiceParameter}; 4 | use crate::DecodeResult; 5 | 6 | use super::Header; 7 | use std::collections::BTreeSet; 8 | 9 | impl<'a, 'b: 'a> Decoder<'b, 'b> { 10 | /// Decode a Service Binding (SVCB or HTTP) resource record 11 | /// 12 | /// Preconditions 13 | /// * The header and question sections should have already been decoded. Specifically, index of 14 | /// any previously-identified domain names must already be captured. 15 | /// 16 | /// Parameters 17 | /// - `header` - the header that precedes the question section 18 | /// - `https` - true for `HTTPS` resource records, false for `SVCB` 19 | pub(super) fn rr_service_binding( 20 | &'a mut self, 21 | header: Header, 22 | https: bool, 23 | ) -> DecodeResult { 24 | let priority = self.u16()?; 25 | let target_name = self.domain_name()?; 26 | let mut parameters = BTreeSet::new(); 27 | if priority != 0 { 28 | while !self.is_finished()? { 29 | let service_parameter_key = self.u16()?; 30 | let value_length = self.u16()?; 31 | let mut parameter_decoder = self.sub(value_length)?; 32 | let service_parameter = 33 | parameter_decoder.rr_service_parameter(service_parameter_key)?; 34 | parameter_decoder.finished()?; 35 | 36 | parameters.insert(service_parameter); 37 | } 38 | } 39 | Ok(ServiceBinding { 40 | name: header.domain_name, 41 | ttl: header.ttl, 42 | priority, 43 | target_name, 44 | parameters, 45 | https, 46 | }) 47 | } 48 | } 49 | 50 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 51 | /// Decode a single service parameter 52 | /// 53 | /// Parameters: 54 | /// - `service_parameter_key` - the IANA-controlled numeric identifier as defined in section 55 | /// 14.3 of the RFC 56 | /// 57 | /// Returns: 58 | /// - `Ok(ServiceParameter)` - if there were no issues decoding the value 59 | /// - `Err` - if there was any decoding error 60 | fn rr_service_parameter( 61 | &mut self, 62 | service_parameter_key: u16, 63 | ) -> DecodeResult { 64 | let service_parameter = match service_parameter_key { 65 | 0 => { 66 | let mut key_ids = vec![]; 67 | while !self.is_finished()? { 68 | key_ids.push(self.u16()?); 69 | } 70 | ServiceParameter::MANDATORY { key_ids } 71 | } 72 | 1 => { 73 | let mut alpn_ids = vec![]; 74 | while !self.is_finished()? { 75 | alpn_ids.push(self.string()?); 76 | } 77 | ServiceParameter::ALPN { alpn_ids } 78 | } 79 | 2 => ServiceParameter::NO_DEFAULT_ALPN, 80 | 3 => ServiceParameter::PORT { port: self.u16()? }, 81 | 4 => { 82 | let mut hints = vec![]; 83 | while !self.is_finished()? { 84 | hints.push(self.ipv4_addr()?); 85 | } 86 | ServiceParameter::IPV4_HINT { hints } 87 | } 88 | 5 => { 89 | // Note the RFC does not explicitly state that the length is two octets 90 | // "In wire format, the value of the parameter is an ECHConfigList [ECH], 91 | // including the redundant length prefix." - RFC Section 9 92 | let length = self.u16()? as usize; 93 | let config_list = self.vec()?; 94 | if config_list.len() != length { 95 | return Err(ECHLengthMismatch(length, config_list.len())); 96 | } 97 | ServiceParameter::ECH { config_list } 98 | } 99 | 6 => { 100 | let mut hints = vec![]; 101 | while !self.is_finished()? { 102 | hints.push(self.ipv6_addr()?); 103 | } 104 | ServiceParameter::IPV6_HINT { hints } 105 | } 106 | 65535 => ServiceParameter::KEY_65535, 107 | number => ServiceParameter::PRIVATE { 108 | number, 109 | wire_data: self.vec()?, 110 | }, 111 | }; 112 | Ok(service_parameter) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/decode/rr/edns/mod.rs: -------------------------------------------------------------------------------- 1 | mod rfc_6891; 2 | mod rfc_7830; 3 | mod rfc_7871; 4 | mod rfc_7873; 5 | -------------------------------------------------------------------------------- /src/decode/rr/edns/rfc_6891.rs: -------------------------------------------------------------------------------- 1 | use super::super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::edns::{EDNSOption, EDNSOptionCode, EDNS_DNSSEC_MASK}; 4 | use crate::rr::OPT; 5 | use crate::{DecodeError, DecodeResult}; 6 | use std::convert::TryFrom; 7 | 8 | fn rr_opt_ttl(ttl: u32) -> DecodeResult<(u8, u8, bool)> { 9 | let extend_rcode = ((ttl >> 24) & 0xff) as u8; 10 | let version = ((ttl >> 16) & 0xff) as u8; 11 | let buffer = ((ttl >> 8) & 0xff) as u8; 12 | let dnssec = match buffer { 13 | 0x00 => false, 14 | EDNS_DNSSEC_MASK => true, 15 | buffer => return Err(DecodeError::OPTZero(buffer)), 16 | }; 17 | let buffer = (ttl & 0xff) as u8; 18 | if buffer != 0 { 19 | return Err(DecodeError::OPTZero(buffer)); 20 | } 21 | Ok((extend_rcode, version, dnssec)) 22 | } 23 | 24 | impl<'a, 'b: 'a> Decoder<'b, 'b> { 25 | fn rr_edns_option(&'a mut self) -> DecodeResult { 26 | let edns_option_code = self.rr_edns_option_code()?; 27 | let edns_option_length = self.u16()?; 28 | let mut ends_option_data = self.sub(edns_option_length)?; 29 | let edns_option = match edns_option_code { 30 | EDNSOptionCode::ECS => EDNSOption::ECS(ends_option_data.rr_edns_ecs()?), 31 | EDNSOptionCode::Cookie => EDNSOption::Cookie(ends_option_data.rr_edns_cookie()?), 32 | EDNSOptionCode::Padding => EDNSOption::Padding(ends_option_data.rr_edns_padding()?), 33 | }; 34 | ends_option_data.finished()?; 35 | Ok(edns_option) 36 | } 37 | 38 | pub(in super::super) fn rr_opt(&'a mut self, header: Header) -> DecodeResult { 39 | if !header.domain_name.is_root() { 40 | return Err(DecodeError::OPTDomainName(header.domain_name)); 41 | } 42 | let requestor_payload_size = header.class; 43 | // TODO 44 | let (extend_rcode, version, dnssec) = rr_opt_ttl(header.ttl)?; 45 | let mut edns_options = Vec::new(); 46 | while !self.is_finished()? { 47 | edns_options.push(self.rr_edns_option()?); 48 | } 49 | let opt = OPT { 50 | requestor_payload_size, 51 | extend_rcode, 52 | version, 53 | dnssec, 54 | edns_options, 55 | }; 56 | Ok(opt) 57 | } 58 | } 59 | 60 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 61 | fn rr_edns_option_code(&mut self) -> DecodeResult { 62 | let buffer = self.u16()?; 63 | match EDNSOptionCode::try_from(buffer) { 64 | Ok(ends_option_code) => Ok(ends_option_code), 65 | Err(buffer) => Err(DecodeError::EDNSOptionCode(buffer)), 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/decode/rr/edns/rfc_7830.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::rr::edns::Padding; 3 | use crate::{DecodeError, DecodeResult}; 4 | use std::convert::TryInto; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_edns_padding(&mut self) -> DecodeResult { 8 | let padding = self.vec()?; 9 | let padding_len = padding.len(); 10 | match padding_len.try_into() { 11 | Ok(padding_len) => { 12 | for b in &padding { 13 | if *b != 0 { 14 | return Err(DecodeError::PaddingZero(*b)); 15 | } 16 | } 17 | Ok(Padding(padding_len)) 18 | } 19 | Err(_) => Err(DecodeError::PaddingLength(padding_len)), 20 | } 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | static MAX_PADDING: [u8; 65536] = [0; 65536]; 26 | 27 | #[test] 28 | fn rr_edns_padding_length() { 29 | use bytes::Bytes; 30 | let bytes = Bytes::from_static(&MAX_PADDING[..]); 31 | let mut decoder = Decoder::main(bytes); 32 | assert_eq!( 33 | decoder.rr_edns_padding(), 34 | Err(DecodeError::PaddingLength(65536)) 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/decode/rr/edns/rfc_7871.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::rr::edns::ECS; 3 | use crate::DecodeResult; 4 | 5 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 6 | pub(super) fn rr_edns_ecs(&mut self) -> DecodeResult { 7 | let address_family_number = self.rr_address_family_number()?; 8 | let source_prefix_length = self.u8()?; 9 | let scope_prefix_length = self.u8()?; 10 | let address = self.rr_address(address_family_number)?; 11 | let ecs = ECS::new(source_prefix_length, scope_prefix_length, address)?; 12 | Ok(ecs) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/decode/rr/edns/rfc_7873.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::rr::edns::{ 3 | Cookie, CLIENT_COOKIE_LENGTH, MAXIMUM_SERVER_COOKIE_LENGTH, MINIMUM_SERVER_COOKIE_LENGTH, 4 | }; 5 | use crate::{DecodeError, DecodeResult}; 6 | use std::convert::TryInto; 7 | 8 | const MINIMUM_COOKIE_LENGTH: usize = CLIENT_COOKIE_LENGTH + MINIMUM_SERVER_COOKIE_LENGTH; 9 | const MAXIMUM_COOKIE_LENGTH: usize = CLIENT_COOKIE_LENGTH + MAXIMUM_SERVER_COOKIE_LENGTH; 10 | 11 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 12 | pub(super) fn rr_edns_cookie(&mut self) -> DecodeResult { 13 | let vec = self.vec()?; 14 | let vec_len = vec.len(); 15 | 16 | if CLIENT_COOKIE_LENGTH == vec_len { 17 | let client_cookie = vec[0..8].try_into().unwrap(); 18 | let cookie = Cookie::new(client_cookie, None)?; 19 | Ok(cookie) 20 | } else if (MINIMUM_COOKIE_LENGTH..MAXIMUM_COOKIE_LENGTH).contains(&vec_len) { 21 | let client_cookie = vec[0..8].try_into().unwrap(); 22 | let server_cookie = Some(vec[8..].to_vec()); 23 | let cookie = Cookie::new(client_cookie, server_cookie)?; 24 | Ok(cookie) 25 | } else { 26 | Err(DecodeError::CookieLength(vec_len)) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/decode/rr/enums.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::rr::{Class, Type, RR}; 3 | use crate::{DecodeError, DecodeResult, DomainName}; 4 | use std::convert::TryFrom; 5 | 6 | pub(super) struct Header { 7 | pub(super) domain_name: DomainName, 8 | pub(super) class: u16, 9 | pub(super) ttl: u32, 10 | } 11 | 12 | impl Header { 13 | pub(super) fn get_class(&self) -> DecodeResult { 14 | match Class::try_from(self.class) { 15 | Ok(class) => Ok(class), 16 | Err(buffer) => Err(DecodeError::Class(buffer)), 17 | } 18 | } 19 | } 20 | 21 | impl<'a, 'b: 'a> Decoder<'b, 'b> { 22 | fn rr_data(&'a mut self) -> DecodeResult> { 23 | let rd_length = self.u16()?; 24 | let r_data = self.sub(rd_length)?; 25 | Ok(r_data) 26 | } 27 | 28 | pub fn rr(&'a mut self) -> DecodeResult { 29 | let (type_, header) = self.rr_header()?; 30 | let mut r_data = self.rr_data()?; 31 | let rr = match type_ { 32 | Type::A => RR::A(r_data.rr_a(header)?), 33 | Type::NS => RR::NS(r_data.rr_ns(header)?), 34 | Type::MD => RR::MD(r_data.rr_md(header)?), 35 | Type::MF => RR::MF(r_data.rr_mf(header)?), 36 | Type::CNAME => RR::CNAME(r_data.rr_cname(header)?), 37 | Type::SOA => RR::SOA(r_data.rr_soa(header)?), 38 | Type::MB => RR::MB(r_data.rr_mb(header)?), 39 | Type::MG => RR::MG(r_data.rr_mg(header)?), 40 | Type::MR => RR::MR(r_data.rr_mr(header)?), 41 | Type::NULL => RR::NULL(r_data.rr_null(header)?), 42 | Type::WKS => RR::WKS(r_data.rr_wks(header)?), 43 | Type::PTR => RR::PTR(r_data.rr_ptr(header)?), 44 | Type::HINFO => RR::HINFO(r_data.rr_hinfo(header)?), 45 | Type::MINFO => RR::MINFO(r_data.rr_minfo(header)?), 46 | Type::MX => RR::MX(r_data.rr_mx(header)?), 47 | Type::TXT => RR::TXT(r_data.rr_txt(header)?), 48 | Type::RP => RR::RP(r_data.rr_rp(header)?), 49 | Type::AFSDB => RR::AFSDB(r_data.rr_afsdb(header)?), 50 | Type::X25 => RR::X25(r_data.rr_x25(header)?), 51 | Type::ISDN => RR::ISDN(r_data.rr_isdn(header)?), 52 | Type::RT => RR::RT(r_data.rr_rt(header)?), 53 | Type::NSAP => RR::NSAP(r_data.rr_nsap(header)?), 54 | Type::GPOS => RR::GPOS(r_data.rr_gpos(header)?), 55 | Type::LOC => RR::LOC(r_data.rr_loc(header)?), 56 | Type::PX => RR::PX(r_data.rr_px(header)?), 57 | Type::KX => RR::KX(r_data.rr_kx(header)?), 58 | Type::SRV => RR::SRV(r_data.rr_srv(header)?), 59 | Type::AAAA => RR::AAAA(r_data.rr_aaaa(header)?), 60 | Type::SSHFP => RR::SSHFP(r_data.rr_sshfp(header)?), 61 | Type::DNAME => RR::DNAME(r_data.rr_dname(header)?), 62 | Type::OPT => RR::OPT(r_data.rr_opt(header)?), 63 | Type::APL => RR::APL(r_data.rr_apl(header)?), 64 | Type::NID => RR::NID(r_data.rr_nid(header)?), 65 | Type::L32 => RR::L32(r_data.rr_l32(header)?), 66 | Type::L64 => RR::L64(r_data.rr_l64(header)?), 67 | Type::LP => RR::LP(r_data.rr_lp(header)?), 68 | Type::EUI48 => RR::EUI48(r_data.rr_eui48(header)?), 69 | Type::EUI64 => RR::EUI64(r_data.rr_eui64(header)?), 70 | Type::URI => RR::URI(r_data.rr_uri(header)?), 71 | Type::EID => RR::EID(r_data.rr_eid(header)?), 72 | Type::NIMLOC => RR::NIMLOC(r_data.rr_nimloc(header)?), 73 | Type::DNSKEY => RR::DNSKEY(r_data.rr_dnskey(header)?), 74 | Type::DS => RR::DS(r_data.rr_ds(header)?), 75 | Type::CAA => RR::CAA(r_data.rr_caa(header)?), 76 | Type::SVCB => RR::SVCB(r_data.rr_service_binding(header, false)?), 77 | Type::HTTPS => RR::HTTPS(r_data.rr_service_binding(header, true)?), 78 | type_ => return Err(DecodeError::NotYetImplemented(type_)), 79 | }; 80 | r_data.finished()?; 81 | Ok(rr) 82 | } 83 | } 84 | 85 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 86 | fn rr_header(&mut self) -> DecodeResult<(Type, Header)> { 87 | let domain_name = self.domain_name()?; 88 | let type_ = self.rr_type()?; 89 | let class = self.u16()?; 90 | let ttl = self.u32()?; 91 | let header = Header { 92 | domain_name, 93 | class, 94 | ttl, 95 | }; 96 | Ok((type_, header)) 97 | } 98 | 99 | pub fn rr_class(&mut self) -> DecodeResult { 100 | let buffer = self.u16()?; 101 | match Class::try_from(buffer) { 102 | Ok(class) => Ok(class), 103 | Err(buffer) => Err(DecodeError::Class(buffer)), 104 | } 105 | } 106 | 107 | pub fn rr_type(&mut self) -> DecodeResult { 108 | let buffer = self.u16()?; 109 | match Type::try_from(buffer) { 110 | Ok(type_) => Ok(type_), 111 | Err(buffer) => Err(DecodeError::Type(buffer)), 112 | } 113 | } 114 | } 115 | 116 | impl_decode!(Class, rr_class); 117 | 118 | impl_decode!(Type, rr_type); 119 | 120 | impl_decode!(RR, rr); 121 | -------------------------------------------------------------------------------- /src/decode/rr/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_decode_rr_domain_name { 2 | ($i:ident, $n:ident, $m:ident) => { 3 | pub(super) fn $m( 4 | &mut self, 5 | header: super::enums::Header, 6 | ) -> crate::DecodeResult { 7 | let class = header.get_class()?; 8 | let $n = self.domain_name()?; 9 | let v = crate::rr::$i { 10 | domain_name: header.domain_name, 11 | ttl: header.ttl, 12 | class, 13 | $n, 14 | }; 15 | Ok(v) 16 | } 17 | }; 18 | } 19 | 20 | macro_rules! impl_decode_rr_u16_domain_name { 21 | ($i:ident, $p:ident, $n:ident, $m:ident) => { 22 | pub(super) fn $m( 23 | &mut self, 24 | header: super::enums::Header, 25 | ) -> crate::DecodeResult { 26 | let class = header.get_class()?; 27 | let $p = self.u16()?; 28 | let $n = self.domain_name()?; 29 | let v = crate::rr::$i { 30 | domain_name: header.domain_name, 31 | ttl: header.ttl, 32 | class, 33 | $p, 34 | $n, 35 | }; 36 | Ok(v) 37 | } 38 | }; 39 | } 40 | 41 | macro_rules! impl_decode_rr_u16_u64 { 42 | ($i:ident, $p:ident, $n:ident, $m:ident) => { 43 | pub(super) fn $m( 44 | &mut self, 45 | header: super::enums::Header, 46 | ) -> crate::DecodeResult { 47 | let class = header.get_class()?; 48 | let $p = self.u16()?; 49 | let $n = self.u64()?; 50 | let v = crate::rr::$i { 51 | domain_name: header.domain_name, 52 | ttl: header.ttl, 53 | class, 54 | $p, 55 | $n, 56 | }; 57 | Ok(v) 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! impl_decode_rr_domain_name_domain_name { 63 | ($i:ident, $p:ident, $n:ident, $m:ident) => { 64 | pub(super) fn $m( 65 | &mut self, 66 | header: super::enums::Header, 67 | ) -> crate::DecodeResult { 68 | let class = header.get_class()?; 69 | let $p = self.domain_name()?; 70 | let $n = self.domain_name()?; 71 | let v = crate::rr::$i { 72 | domain_name: header.domain_name, 73 | ttl: header.ttl, 74 | class, 75 | $p, 76 | $n, 77 | }; 78 | Ok(v) 79 | } 80 | }; 81 | } 82 | 83 | macro_rules! impl_decode_rr_vec { 84 | ($i:ident, $n:ident, $m:ident) => { 85 | pub(super) fn $m( 86 | &mut self, 87 | header: super::enums::Header, 88 | ) -> crate::DecodeResult { 89 | let class = header.get_class()?; 90 | let $n = self.vec()?; 91 | let v = crate::rr::$i { 92 | domain_name: header.domain_name, 93 | ttl: header.ttl, 94 | class, 95 | $n, 96 | }; 97 | Ok(v) 98 | } 99 | }; 100 | } 101 | -------------------------------------------------------------------------------- /src/decode/rr/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | mod draft_ietf_dnsop_svcb_https; 4 | mod edns; 5 | mod enums; 6 | mod rfc_1035; 7 | mod rfc_1183; 8 | mod rfc_1706; 9 | mod rfc_1712; 10 | mod rfc_1876; 11 | mod rfc_2163; 12 | mod rfc_2230; 13 | mod rfc_2782; 14 | mod rfc_3123; 15 | mod rfc_3596; 16 | mod rfc_3658; 17 | mod rfc_4034; 18 | mod rfc_6672; 19 | mod rfc_6742; 20 | mod rfc_7043; 21 | mod rfc_7553; 22 | mod rfc_8659; 23 | mod subtypes; 24 | #[cfg(test)] 25 | mod tests; 26 | mod unknown; 27 | 28 | use enums::Header; 29 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_1035.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{Class, A, HINFO, SOA, TXT, WKS}; 4 | use crate::{DecodeError, DecodeResult}; 5 | use std::convert::TryInto; 6 | 7 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 8 | pub(super) fn rr_a(&mut self, header: Header) -> DecodeResult { 9 | match header.get_class()? { 10 | Class::IN => { 11 | let ipv4_addr = self.ipv4_addr()?; 12 | let a = A { 13 | domain_name: header.domain_name, 14 | ttl: header.ttl, 15 | ipv4_addr, 16 | }; 17 | Ok(a) 18 | } 19 | class => Err(DecodeError::AClass(class)), 20 | } 21 | } 22 | 23 | impl_decode_rr_domain_name!(NS, ns_d_name, rr_ns); 24 | 25 | impl_decode_rr_domain_name!(MD, mad_name, rr_md); 26 | 27 | impl_decode_rr_domain_name!(MF, mad_name, rr_mf); 28 | 29 | impl_decode_rr_domain_name!(CNAME, c_name, rr_cname); 30 | 31 | pub(super) fn rr_soa(&mut self, header: Header) -> DecodeResult { 32 | let class = header.get_class()?; 33 | let m_name = self.domain_name()?; 34 | let r_name = self.domain_name()?; 35 | let serial = self.u32()?; 36 | let refresh = self.u32()?; 37 | let retry = self.u32()?; 38 | let expire = self.u32()?; 39 | let min_ttl = self.u32()?; 40 | 41 | let soa = SOA { 42 | domain_name: header.domain_name, 43 | ttl: header.ttl, 44 | class, 45 | m_name, 46 | r_name, 47 | serial, 48 | refresh, 49 | retry, 50 | expire, 51 | min_ttl, 52 | }; 53 | 54 | Ok(soa) 55 | } 56 | 57 | impl_decode_rr_domain_name!(MB, mad_name, rr_mb); 58 | 59 | impl_decode_rr_domain_name!(MG, mgm_name, rr_mg); 60 | 61 | impl_decode_rr_domain_name!(MR, new_name, rr_mr); 62 | 63 | impl_decode_rr_vec!(NULL, data, rr_null); 64 | 65 | pub(super) fn rr_wks(&mut self, header: Header) -> DecodeResult { 66 | match header.get_class()? { 67 | Class::IN => { 68 | let ipv4_addr = self.ipv4_addr()?; 69 | let protocol = self.u8()?; 70 | let bit_map = self.vec()?; 71 | let wks = WKS { 72 | domain_name: header.domain_name, 73 | ttl: header.ttl, 74 | ipv4_addr, 75 | protocol, 76 | bit_map, 77 | }; 78 | Ok(wks) 79 | } 80 | class => Err(DecodeError::WKSClass(class)), 81 | } 82 | } 83 | 84 | impl_decode_rr_domain_name!(PTR, ptr_d_name, rr_ptr); 85 | 86 | pub(super) fn rr_hinfo(&mut self, header: Header) -> DecodeResult { 87 | let class = header.get_class()?; 88 | let cpu = self.string()?; 89 | let os = self.string()?; 90 | let hinfo = HINFO { 91 | domain_name: header.domain_name, 92 | ttl: header.ttl, 93 | class, 94 | cpu, 95 | os, 96 | }; 97 | Ok(hinfo) 98 | } 99 | 100 | impl_decode_rr_domain_name_domain_name!(MINFO, r_mail_bx, e_mail_bx, rr_minfo); 101 | 102 | impl_decode_rr_u16_domain_name!(MX, preference, exchange, rr_mx); 103 | 104 | pub(super) fn rr_txt(&mut self, header: Header) -> DecodeResult { 105 | let class = header.get_class()?; 106 | let mut strings = Vec::new(); 107 | while !self.is_finished()? { 108 | strings.push(self.string()?); 109 | } 110 | let strings = strings.try_into().map_err(|_| DecodeError::TXTEmpty)?; 111 | let txt = TXT { 112 | domain_name: header.domain_name, 113 | ttl: header.ttl, 114 | class, 115 | strings, 116 | }; 117 | Ok(txt) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_1183.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{AFSDBSubtype, ISDNAddress, PSDNAddress, AFSDB, ISDN, SA, X25}; 4 | use crate::{DecodeError, DecodeResult}; 5 | use std::convert::TryFrom; 6 | 7 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 8 | impl_decode_rr_domain_name_domain_name!(RP, mbox_dname, txt_dname, rr_rp); 9 | 10 | fn rr_afsdb_subtype(&mut self) -> DecodeResult { 11 | let buffer = self.u16()?; 12 | match AFSDBSubtype::try_from(buffer) { 13 | Ok(afs_db_subtype) => Ok(afs_db_subtype), 14 | Err(buffer) => Err(DecodeError::AFSDBSubtype(buffer)), 15 | } 16 | } 17 | 18 | pub(super) fn rr_afsdb(&mut self, header: Header) -> DecodeResult { 19 | let class = header.get_class()?; 20 | let subtype = self.rr_afsdb_subtype()?; 21 | let hostname = self.domain_name()?; 22 | let afs_db = AFSDB { 23 | domain_name: header.domain_name, 24 | ttl: header.ttl, 25 | class, 26 | subtype, 27 | hostname, 28 | }; 29 | Ok(afs_db) 30 | } 31 | 32 | pub(super) fn rr_x25(&mut self, header: Header) -> DecodeResult { 33 | let class = header.get_class()?; 34 | let psdn_address = self.string()?; 35 | let psdn_address = PSDNAddress::try_from(psdn_address)?; 36 | 37 | let x25 = X25 { 38 | domain_name: header.domain_name, 39 | ttl: header.ttl, 40 | class, 41 | psdn_address, 42 | }; 43 | Ok(x25) 44 | } 45 | 46 | pub(super) fn rr_isdn(&mut self, header: Header) -> DecodeResult { 47 | let class = header.get_class()?; 48 | let isdn_address = self.string()?; 49 | let isdn_address = ISDNAddress::try_from(isdn_address)?; 50 | 51 | let sa = if self.is_finished()? { 52 | None 53 | } else { 54 | let sa = self.string()?; 55 | let sa = SA::try_from(sa)?; 56 | Some(sa) 57 | }; 58 | 59 | let isdn = ISDN { 60 | domain_name: header.domain_name, 61 | ttl: header.ttl, 62 | class, 63 | isdn_address, 64 | sa, 65 | }; 66 | Ok(isdn) 67 | } 68 | 69 | impl_decode_rr_u16_domain_name!(RT, preference, intermediate_host, rr_rt); 70 | } 71 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_1706.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | 3 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 4 | impl_decode_rr_vec!(NSAP, data, rr_nsap); 5 | } 6 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_1712.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::GPOS; 4 | use crate::{DecodeError, DecodeResult}; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_gpos(&mut self, header: Header) -> DecodeResult { 8 | let class = header.get_class()?; 9 | 10 | // TODO String value check 11 | let longitude = self.string()?; 12 | let longitude_len = longitude.len(); 13 | if !(1..=256).contains(&longitude_len) { 14 | return Err(DecodeError::GPOS); 15 | } 16 | 17 | let latitude = self.string()?; 18 | let latitude_len = latitude.len(); 19 | if !(1..=256).contains(&latitude_len) { 20 | return Err(DecodeError::GPOS); 21 | } 22 | 23 | let altitude = self.string()?; 24 | let altitude_len = altitude.len(); 25 | if !(1..=256).contains(&altitude_len) { 26 | return Err(DecodeError::GPOS); 27 | } 28 | 29 | let gpos = GPOS { 30 | domain_name: header.domain_name, 31 | ttl: header.ttl, 32 | class, 33 | longitude, 34 | latitude, 35 | altitude, 36 | }; 37 | Ok(gpos) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_1876.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::LOC; 4 | use crate::DecodeResult; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_loc(&mut self, header: Header) -> DecodeResult { 8 | let class = header.get_class()?; 9 | 10 | let version = self.u8()?; 11 | let size = self.u8()?; 12 | let horiz_pre = self.u8()?; 13 | let vert_pre = self.u8()?; 14 | 15 | let latitube = self.u32()?; 16 | let longitube = self.u32()?; 17 | let altitube = self.u32()?; 18 | 19 | let loc = LOC { 20 | domain_name: header.domain_name, 21 | ttl: header.ttl, 22 | class, 23 | version, 24 | size, 25 | horiz_pre, 26 | vert_pre, 27 | latitube, 28 | longitube, 29 | altitube, 30 | }; 31 | Ok(loc) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_2163.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::PX; 4 | use crate::DecodeResult; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_px(&mut self, header: Header) -> DecodeResult { 8 | let class = header.get_class()?; 9 | 10 | let preference = self.u16()?; 11 | let map822 = self.domain_name()?; 12 | let mapx400 = self.domain_name()?; 13 | let px = PX { 14 | domain_name: header.domain_name, 15 | ttl: header.ttl, 16 | class, 17 | preference, 18 | map822, 19 | mapx400, 20 | }; 21 | Ok(px) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_2230.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | 3 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 4 | impl_decode_rr_u16_domain_name!(KX, preference, exchanger, rr_kx); 5 | } 6 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_2782.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::SRV; 4 | use crate::DecodeResult; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_srv(&mut self, header: Header) -> DecodeResult { 8 | let class = header.get_class()?; 9 | let priority = self.u16()?; 10 | let weight = self.u16()?; 11 | let port = self.u16()?; 12 | let target = self.domain_name()?; 13 | let srv = SRV { 14 | domain_name: header.domain_name, 15 | ttl: header.ttl, 16 | class, 17 | priority, 18 | weight, 19 | port, 20 | target, 21 | }; 22 | Ok(srv) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_3123.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{APItem, Class, APL, APL_NEGATION_MASK}; 4 | use crate::{DecodeError, DecodeResult}; 5 | 6 | const ADDRESS_LENGTH_MASK: u8 = 0b0111_1111; 7 | 8 | impl<'a, 'b: 'a> Decoder<'b, 'b> { 9 | pub(super) fn rr_apl_apitem(&'a mut self) -> DecodeResult { 10 | let address_family_number = self.rr_address_family_number()?; 11 | let prefix = self.u8()?; 12 | let buffer = self.u8()?; 13 | let negation = (buffer & APL_NEGATION_MASK) == APL_NEGATION_MASK; 14 | let address_length = buffer & ADDRESS_LENGTH_MASK; 15 | let mut address_data = self.sub(address_length as u16)?; 16 | let address = address_data.rr_address(address_family_number)?; 17 | address_data.finished()?; 18 | let apitem = APItem::new(prefix, negation, address)?; 19 | Ok(apitem) 20 | } 21 | 22 | pub(super) fn rr_apl(&'a mut self, header: Header) -> DecodeResult { 23 | match header.get_class()? { 24 | Class::IN => { 25 | let mut apitems = Vec::new(); 26 | while !self.is_finished()? { 27 | apitems.push(self.rr_apl_apitem()?); 28 | } 29 | let apl = APL { 30 | domain_name: header.domain_name, 31 | ttl: header.ttl, 32 | apitems, 33 | }; 34 | Ok(apl) 35 | } 36 | class => Err(DecodeError::APLClass(class)), 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_3596.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{Class, AAAA}; 4 | use crate::{DecodeError, DecodeResult}; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_aaaa(&mut self, header: Header) -> DecodeResult { 8 | match header.get_class()? { 9 | Class::IN => { 10 | let ipv6_addr = self.ipv6_addr()?; 11 | let aaaa = AAAA { 12 | domain_name: header.domain_name, 13 | ttl: header.ttl, 14 | ipv6_addr, 15 | }; 16 | Ok(aaaa) 17 | } 18 | class => Err(DecodeError::AAAAClass(class)), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_3658.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{SSHFPAlgorithm, SSHFPType, SSHFP}; 4 | use crate::{DecodeError, DecodeResult}; 5 | use std::convert::TryFrom; 6 | 7 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 8 | fn rr_sshfp_algorithm(&mut self) -> DecodeResult { 9 | let buffer = self.u8()?; 10 | match SSHFPAlgorithm::try_from(buffer) { 11 | Ok(algorithm) => Ok(algorithm), 12 | Err(buffer) => Err(DecodeError::SSHFPAlgorithm(buffer)), 13 | } 14 | } 15 | 16 | fn rr_sshfp_type(&mut self) -> DecodeResult { 17 | let buffer = self.u8()?; 18 | match SSHFPType::try_from(buffer) { 19 | Ok(type_) => Ok(type_), 20 | Err(buffer) => Err(DecodeError::SSHFPType(buffer)), 21 | } 22 | } 23 | 24 | pub(super) fn rr_sshfp(&mut self, header: Header) -> DecodeResult { 25 | let class = header.get_class()?; 26 | let algorithm = self.rr_sshfp_algorithm()?; 27 | let type_ = self.rr_sshfp_type()?; 28 | let fp = self.vec()?; 29 | let ssh_fp = SSHFP { 30 | domain_name: header.domain_name, 31 | ttl: header.ttl, 32 | class, 33 | algorithm, 34 | type_, 35 | fp, 36 | }; 37 | Ok(ssh_fp) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_4034.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::rr::{ 3 | AlgorithmType, DigestType, DNSKEY, DNSKEY_ZERO_MASK, DS, SECURE_ENTRY_POINT_FLAG, ZONE_KEY_FLAG, 4 | }; 5 | use crate::DecodeResult; 6 | use crate::{decode::Decoder, DecodeError}; 7 | use std::convert::TryFrom; 8 | 9 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 10 | fn rr_algorithm_type(&mut self) -> DecodeResult { 11 | let buffer = self.u8()?; 12 | match AlgorithmType::try_from(buffer) { 13 | Ok(algorithm_type) => Ok(algorithm_type), 14 | Err(buffer) => Err(DecodeError::AlgorithmType(buffer)), 15 | } 16 | } 17 | 18 | fn rr_digest_type(&mut self) -> DecodeResult { 19 | let buffer = self.u8()?; 20 | match DigestType::try_from(buffer) { 21 | Ok(digest_type) => Ok(digest_type), 22 | Err(buffer) => Err(DecodeError::DigestType(buffer)), 23 | } 24 | } 25 | 26 | pub(super) fn rr_dnskey(&mut self, header: Header) -> DecodeResult { 27 | let class = header.get_class()?; 28 | let flags = self.u16()?; 29 | if flags & DNSKEY_ZERO_MASK != 0 { 30 | return Err(DecodeError::DNSKEYZeroFlags(flags)); 31 | } 32 | let zone_key_flag = (flags & ZONE_KEY_FLAG) == ZONE_KEY_FLAG; 33 | let secure_entry_point_flag = (flags & SECURE_ENTRY_POINT_FLAG) == SECURE_ENTRY_POINT_FLAG; 34 | let protocol = self.u8()?; 35 | if protocol != 3 { 36 | return Err(DecodeError::DNSKEYProtocol(protocol)); 37 | } 38 | let algorithm_type = self.rr_algorithm_type()?; 39 | let public_key = self.vec()?; 40 | let dnskey = DNSKEY { 41 | domain_name: header.domain_name, 42 | ttl: header.ttl, 43 | class, 44 | zone_key_flag, 45 | secure_entry_point_flag, 46 | algorithm_type, 47 | public_key, 48 | }; 49 | Ok(dnskey) 50 | } 51 | 52 | pub(super) fn rr_ds(&mut self, header: Header) -> DecodeResult { 53 | let class = header.get_class()?; 54 | let key_tag = self.u16()?; 55 | let algorithm_type = self.rr_algorithm_type()?; 56 | let digest_type = self.rr_digest_type()?; 57 | let digest = self.vec()?; 58 | let ds = DS { 59 | domain_name: header.domain_name, 60 | ttl: header.ttl, 61 | class, 62 | key_tag, 63 | algorithm_type, 64 | digest_type, 65 | digest, 66 | }; 67 | Ok(ds) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_6672.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | 3 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 4 | impl_decode_rr_domain_name!(DNAME, target, rr_dname); 5 | } 6 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_6742.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::L32; 4 | use crate::DecodeResult; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | impl_decode_rr_u16_u64!(NID, preference, node_id, rr_nid); 8 | 9 | pub(super) fn rr_l32(&mut self, header: Header) -> DecodeResult { 10 | let class = header.get_class()?; 11 | let preference = self.u16()?; 12 | let locator_32 = self.u32()?; 13 | let l_32 = L32 { 14 | domain_name: header.domain_name, 15 | ttl: header.ttl, 16 | class, 17 | preference, 18 | locator_32, 19 | }; 20 | Ok(l_32) 21 | } 22 | 23 | impl_decode_rr_u16_u64!(L64, preference, locator_64, rr_l64); 24 | 25 | impl_decode_rr_u16_domain_name!(LP, preference, fqdn, rr_lp); 26 | } 27 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_7043.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{EUI48, EUI64}; 4 | use crate::DecodeResult; 5 | 6 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 7 | pub(super) fn rr_eui48(&mut self, header: Header) -> DecodeResult { 8 | let class = header.get_class()?; 9 | let mut eui_48: [u8; 6] = [0; 6]; 10 | eui_48[0] = self.u8()?; 11 | eui_48[1] = self.u8()?; 12 | eui_48[2] = self.u8()?; 13 | eui_48[3] = self.u8()?; 14 | eui_48[4] = self.u8()?; 15 | eui_48[5] = self.u8()?; 16 | 17 | let eui_48 = EUI48 { 18 | domain_name: header.domain_name, 19 | ttl: header.ttl, 20 | class, 21 | eui_48, 22 | }; 23 | Ok(eui_48) 24 | } 25 | 26 | pub(super) fn rr_eui64(&mut self, header: Header) -> DecodeResult { 27 | let class = header.get_class()?; 28 | let mut eui_64: [u8; 8] = [0; 8]; 29 | eui_64[0] = self.u8()?; 30 | eui_64[1] = self.u8()?; 31 | eui_64[2] = self.u8()?; 32 | eui_64[3] = self.u8()?; 33 | eui_64[4] = self.u8()?; 34 | eui_64[5] = self.u8()?; 35 | eui_64[6] = self.u8()?; 36 | eui_64[7] = self.u8()?; 37 | 38 | let eui_64 = EUI64 { 39 | domain_name: header.domain_name, 40 | ttl: header.ttl, 41 | class, 42 | eui_64, 43 | }; 44 | Ok(eui_64) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_7553.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::URI; 4 | use crate::DecodeResult; 5 | use std::str::from_utf8; 6 | 7 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 8 | pub(super) fn rr_uri(&mut self, header: Header) -> DecodeResult { 9 | let class = header.get_class()?; 10 | let priority = self.u16()?; 11 | let weight = self.u16()?; 12 | let buffer = self.vec()?; 13 | let uri = from_utf8(buffer.as_ref())?.to_owned(); 14 | let uri = URI { 15 | domain_name: header.domain_name, 16 | ttl: header.ttl, 17 | class, 18 | priority, 19 | weight, 20 | uri, 21 | }; 22 | Ok(uri) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/decode/rr/rfc_8659.rs: -------------------------------------------------------------------------------- 1 | use super::Header; 2 | use crate::decode::Decoder; 3 | use crate::rr::{Tag, CAA}; 4 | use crate::DecodeResult; 5 | use std::convert::TryFrom; 6 | 7 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 8 | fn rr_caa_tag(&mut self) -> DecodeResult { 9 | let tag = self.string()?; 10 | let tag = Tag::try_from(tag)?; 11 | Ok(tag) 12 | } 13 | 14 | pub(super) fn rr_caa(&mut self, header: Header) -> DecodeResult { 15 | let class = header.get_class()?; 16 | let flags = self.u8()?; 17 | let tag = self.rr_caa_tag()?; 18 | let value = self.vec()?; 19 | 20 | let caa = CAA { 21 | domain_name: header.domain_name, 22 | ttl: header.ttl, 23 | class, 24 | flags, 25 | tag, 26 | value, 27 | }; 28 | Ok(caa) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/decode/rr/subtypes.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::rr::{Address, AddressFamilyNumber}; 3 | use crate::{DecodeError, DecodeResult}; 4 | use std::convert::TryFrom; 5 | use std::mem::size_of; 6 | use std::net::{Ipv4Addr, Ipv6Addr}; 7 | 8 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 9 | pub(super) fn rr_address_family_number(&mut self) -> DecodeResult { 10 | let buffer = self.u16()?; 11 | match AddressFamilyNumber::try_from(buffer) { 12 | Ok(address_number) => Ok(address_number), 13 | Err(buffer) => Err(DecodeError::EcsAddressNumber(buffer)), 14 | } 15 | } 16 | 17 | fn rr_address_ipv4(&mut self) -> DecodeResult
{ 18 | let buffer = self.vec()?; 19 | let buffer_len = buffer.len(); 20 | if size_of::<[u8; 4]>() < buffer_len { 21 | return Err(DecodeError::EcsTooBigIpv4Address(buffer_len)); 22 | } 23 | 24 | let mut octects: [u8; 4] = [0; 4]; 25 | octects[0..buffer_len].copy_from_slice(&buffer[..]); 26 | 27 | let ipv4_addr = Ipv4Addr::from(octects); 28 | Ok(Address::Ipv4(ipv4_addr)) 29 | } 30 | 31 | fn rr_address_ipv6(&mut self) -> DecodeResult
{ 32 | let buffer = self.vec()?; 33 | let buffer_len = buffer.len(); 34 | if size_of::<[u8; 16]>() < buffer_len { 35 | return Err(DecodeError::EcsTooBigIpv6Address(buffer_len)); 36 | } 37 | 38 | let mut octects: [u8; 16] = [0; 16]; 39 | octects[0..buffer_len].copy_from_slice(&buffer[..]); 40 | 41 | let ipv6_addr = Ipv6Addr::from(octects); 42 | Ok(Address::Ipv6(ipv6_addr)) 43 | } 44 | 45 | pub(super) fn rr_address( 46 | &mut self, 47 | address_number: AddressFamilyNumber, 48 | ) -> DecodeResult
{ 49 | match address_number { 50 | AddressFamilyNumber::Ipv4 => self.rr_address_ipv4(), 51 | AddressFamilyNumber::Ipv6 => self.rr_address_ipv6(), 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/decode/rr/unknown.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | 3 | impl<'a, 'b: 'a> Decoder<'a, 'b> { 4 | impl_decode_rr_vec!(EID, data, rr_eid); 5 | 6 | impl_decode_rr_vec!(NIMLOC, data, rr_nimloc); 7 | } 8 | -------------------------------------------------------------------------------- /src/decode/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::decode::Decoder; 2 | use crate::DecodeError; 3 | use bytes::Bytes; 4 | use std::str::from_utf8; 5 | 6 | #[test] 7 | fn u8_error() { 8 | let bytes = Bytes::copy_from_slice(&b""[..]); 9 | let mut decoder = Decoder::main(bytes); 10 | let result = decoder.u8(); 11 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(0, 1))); 12 | } 13 | 14 | #[test] 15 | fn u16_error() { 16 | let bytes = Bytes::copy_from_slice(&b"\x00"[..]); 17 | let mut decoder = Decoder::main(bytes); 18 | let result = decoder.u16(); 19 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(1, 2))); 20 | } 21 | 22 | #[test] 23 | fn u32_error() { 24 | let bytes = Bytes::copy_from_slice(&b"\x00\x00\x00"[..]); 25 | let mut decoder = Decoder::main(bytes); 26 | let result = decoder.u32(); 27 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(3, 4))); 28 | } 29 | 30 | #[test] 31 | fn string_error_1() { 32 | let bytes = Bytes::copy_from_slice(&b""[..]); 33 | let mut decoder = Decoder::main(bytes); 34 | let result = decoder.string(); 35 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(0, 1))); 36 | } 37 | 38 | #[test] 39 | fn string_error_2() { 40 | let bytes = Bytes::copy_from_slice(&b"\x0f\x41\x42"[..]); 41 | let mut decoder = Decoder::main(bytes); 42 | let result = decoder.string(); 43 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(3, 16))); 44 | } 45 | 46 | #[test] 47 | fn string_error_3() { 48 | let bytes = Bytes::copy_from_slice(&b"\x02\x00\xff"[..]); 49 | let mut decoder = Decoder::main(bytes); 50 | let result = decoder.string(); 51 | let bytes = Bytes::copy_from_slice(&b"\x02\x00\xff"[..]); 52 | let excepted = from_utf8(&bytes[1..]).unwrap_err(); 53 | assert_eq!(result, Err(DecodeError::Utf8Error(excepted))); 54 | } 55 | 56 | #[test] 57 | fn ipv4_addr_1() { 58 | let bytes = Bytes::copy_from_slice(&b""[..]); 59 | let mut decoder = Decoder::main(bytes); 60 | let result = decoder.ipv4_addr(); 61 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(0, 4))); 62 | } 63 | 64 | #[test] 65 | fn ipv4_addr_2() { 66 | let bytes = Bytes::copy_from_slice(&b"\xff"[..]); 67 | let mut decoder = Decoder::main(bytes); 68 | let result = decoder.ipv4_addr(); 69 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(1, 4))); 70 | } 71 | 72 | #[test] 73 | fn ipv4_addr_3() { 74 | let bytes = Bytes::copy_from_slice(&b"\xff\xff"[..]); 75 | let mut decoder = Decoder::main(bytes); 76 | let result = decoder.ipv4_addr(); 77 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(2, 4))); 78 | } 79 | 80 | #[test] 81 | fn ipv4_addr_4() { 82 | let bytes = Bytes::copy_from_slice(&b"\xff\xff\xff"[..]); 83 | let mut decoder = Decoder::main(bytes); 84 | let result = decoder.ipv4_addr(); 85 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(3, 4))); 86 | } 87 | 88 | #[test] 89 | fn ipv6_addr_1() { 90 | let bytes = Bytes::copy_from_slice(&b""[..]); 91 | let mut decoder = Decoder::main(bytes); 92 | let result = decoder.ipv6_addr(); 93 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(0, 2))); 94 | } 95 | 96 | #[test] 97 | fn ipv6_addr_2() { 98 | let bytes = Bytes::copy_from_slice(&b"\xff\xff"[..]); 99 | let mut decoder = Decoder::main(bytes); 100 | let result = decoder.ipv6_addr(); 101 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(2, 4))); 102 | } 103 | 104 | #[test] 105 | fn ipv6_addr_3() { 106 | let bytes = Bytes::copy_from_slice(&b"\xff\xff\xff\xff"[..]); 107 | let mut decoder = Decoder::main(bytes); 108 | let result = decoder.ipv6_addr(); 109 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(4, 6))); 110 | } 111 | 112 | #[test] 113 | fn ipv6_addr_4() { 114 | let bytes = Bytes::copy_from_slice(&b"\xff\xff\xff\xff\xff\xff"[..]); 115 | let mut decoder = Decoder::main(bytes); 116 | let result = decoder.ipv6_addr(); 117 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(6, 8))); 118 | } 119 | 120 | #[test] 121 | fn ipv6_addr_5() { 122 | let bytes = Bytes::copy_from_slice(&b"\xff\xff\xff\xff\xff\xff\xff\xff"[..]); 123 | let mut decoder = Decoder::main(bytes); 124 | let result = decoder.ipv6_addr(); 125 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(8, 10))); 126 | } 127 | 128 | #[test] 129 | fn ipv6_addr_6() { 130 | let bytes = Bytes::copy_from_slice(&b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"[..]); 131 | let mut decoder = Decoder::main(bytes); 132 | let result = decoder.ipv6_addr(); 133 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(10, 12))); 134 | } 135 | 136 | #[test] 137 | fn ipv6_addr_7() { 138 | let bytes = Bytes::copy_from_slice(&b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"[..]); 139 | let mut decoder = Decoder::main(bytes); 140 | let result = decoder.ipv6_addr(); 141 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(12, 14))); 142 | } 143 | 144 | #[test] 145 | fn ipv6_addr_8() { 146 | let bytes = 147 | Bytes::copy_from_slice(&b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"[..]); 148 | let mut decoder = Decoder::main(bytes); 149 | let result = decoder.ipv6_addr(); 150 | assert_eq!(result, Err(DecodeError::NotEnoughBytes(14, 16))); 151 | } 152 | -------------------------------------------------------------------------------- /src/dns.rs: -------------------------------------------------------------------------------- 1 | use crate::question::Question; 2 | use crate::rr::RR; 3 | use crate::{Opcode, RCode}; 4 | use std::fmt::{Display, Formatter, Result as FmtResult}; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq)] 7 | pub struct Flags { 8 | pub qr: bool, 9 | pub opcode: Opcode, 10 | pub aa: bool, 11 | pub tc: bool, 12 | pub rd: bool, 13 | pub ra: bool, 14 | pub ad: bool, // RFC2535 6.1 The AD and CD Header Bits 15 | pub cd: bool, // RFC2535 6.1 The AD and CD Header Bits 16 | pub rcode: RCode, 17 | } 18 | 19 | impl Display for Flags { 20 | fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { 21 | if self.qr { 22 | write!(f, "qr ")?; 23 | } 24 | 25 | write!(f, "{:?} ", self.opcode)?; 26 | 27 | if self.aa { 28 | write!(f, "aa ")?; 29 | } 30 | 31 | if self.tc { 32 | write!(f, "tc ")?; 33 | } 34 | 35 | if self.rd { 36 | write!(f, "rd ")?; 37 | } 38 | 39 | if self.ra { 40 | write!(f, "ra ")?; 41 | } 42 | 43 | if self.ad { 44 | write!(f, "ad ")?; 45 | } 46 | 47 | if self.cd { 48 | write!(f, "cd ")?; 49 | } 50 | 51 | write!(f, "{:?}", self.rcode) 52 | } 53 | } 54 | 55 | #[derive(Debug, Clone, PartialEq, Eq)] 56 | pub struct Dns { 57 | pub id: u16, 58 | pub flags: Flags, 59 | pub questions: Vec, 60 | pub answers: Vec, 61 | pub authorities: Vec, 62 | pub additionals: Vec, 63 | } 64 | 65 | impl Dns { 66 | #[inline] 67 | pub const fn is_response(&self) -> bool { 68 | self.flags.qr 69 | } 70 | } 71 | 72 | #[inline] 73 | fn print_slice(f: &mut Formatter<'_>, slice: &[T]) -> FmtResult 74 | where 75 | T: Display, 76 | { 77 | write!(f, "[")?; 78 | for e in slice { 79 | write!(f, "{}, ", e)?; 80 | } 81 | write!(f, "]")?; 82 | Ok(()) 83 | } 84 | 85 | impl Display for Dns { 86 | fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { 87 | write!(f, "{} {} ", self.id, self.flags)?; 88 | 89 | if !self.questions.is_empty() { 90 | write!(f, "questions ")?; 91 | print_slice(f, &self.questions)?; 92 | write!(f, " ")?; 93 | } 94 | 95 | if !self.answers.is_empty() { 96 | write!(f, "answers ")?; 97 | print_slice(f, &self.answers)?; 98 | write!(f, " ")?; 99 | } 100 | 101 | if !self.authorities.is_empty() { 102 | write!(f, "authorities ")?; 103 | print_slice(f, &self.authorities)?; 104 | write!(f, " ")?; 105 | } 106 | 107 | if !self.additionals.is_empty() { 108 | write!(f, "additionals ")?; 109 | print_slice(f, &self.additionals)?; 110 | } 111 | 112 | Ok(()) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/domain_name.rs: -------------------------------------------------------------------------------- 1 | use crate::{Label, LabelError}; 2 | use std::{ 3 | fmt::{Display, Formatter, Result as FmtResult}, 4 | hash::Hash, 5 | str::FromStr, 6 | }; 7 | use thiserror::Error; 8 | 9 | pub const DOMAIN_NAME_MAX_RECURSION: usize = 16; 10 | pub const DOMAIN_NAME_MAX_LENGTH: usize = 256; 11 | 12 | #[derive(Debug, PartialEq, Eq, Error)] 13 | pub enum DomainNameError { 14 | #[error("Domain name is too big: {DOMAIN_NAME_MAX_LENGTH} <= {0}")] 15 | DomainNameLength(usize), 16 | #[error("{0}")] 17 | LabelError(#[from] LabelError), 18 | } 19 | 20 | /// Represent a domain name according to [RFC 2181](https://datatracker.ietf.org/doc/html/rfc2181#section-11). 21 | #[derive(Debug, Clone, PartialEq, Eq, Default, Hash)] 22 | pub struct DomainName(pub(super) Vec