1 unstable release
0.1.0-alpha.5 | Jan 28, 2021 |
---|
#2 in #question
44KB
853 lines
Crabby DNS
A simple DNS server in Rust to help contribute further understanding to my team's office hours discussions.
I made significant reference to the following projects and/or documents in building this:
How to build it
- Use rustup to install the rust toolchain on your local machine.
- Navigate to your checked out repo and run
cargo build
How to get oriented with the crate
- Use
cargo doc --open
to generate crate documentation and view it.
How to run it
- The unit test suite can be run using
cargo test
- For actually running it, see what you can do with
cargo run -- --help
as well as the sections below.
DNS Stub Resolver
Right now the Crabby DNS stub resolver implements some of the most basic relevant pieces of
IETF RFC 1035, and probably not even that correctly.
Only A
RRs of class IN
are currently supported.
Via the CLI, you specify a query domain name, and optionally a query type and query class. The stub resolver will delegate interface address binding and port selection for the UDP socket to the OS. Your query will be serialized into a DNS protocol message of query type with a header and question section and sent to the configured DNS server. The response will then be listened for (blocking) and deserialized into a DNS protocol message of response type with whatever sections + data the server responded with.
- Invoke subcommand-specific help via
cargo run -- stub --help
Example
$ cargo run -- stub -@ 8.8.8.8 -d google.com
Connected to 8.8.8.8:53 from 10.0.2.15:43506
Working on the DNS transaction now...
#################################################
# DNS QUESTION MESSAGE #
#################################################
Header {
id: 0,
message_type: Query,
op_code: Query,
authoritative_answer: false,
truncation: false,
recursion_desired: true,
recursion_available: false,
authentic_data: false,
checking_disabled: false,
response_code: NoError,
question_count: 1,
answer_count: 0,
authority_count: 0,
additional_count: 0,
}
Question {
domain_name: DomainName(
"google.com",
),
qtype: RRType(
A,
),
qclass: RRClass(
IN,
),
}
#################################################
# DNS RESPONSE MESSAGE #
#################################################
Header {
id: 0,
message_type: Response,
op_code: Query,
authoritative_answer: false,
truncation: false,
recursion_desired: true,
recursion_available: true,
authentic_data: false,
checking_disabled: false,
response_code: NoError,
question_count: 1,
answer_count: 1,
authority_count: 0,
additional_count: 0,
}
Question {
domain_name: DomainName(
"google.com",
),
qtype: RRType(
A,
),
qclass: RRClass(
IN,
),
}
ResourceRecord {
domain_name: DomainName(
"google.com",
),
rrtype: A,
rrclass: IN,
ttl: 102,
rrdata_len: 4,
rrdata: A(
172.217.3.110,
),
}
DNS datagram deserializer
- Invoke subcommand-specific help via
cargo run -- deserialize --help
- You'll need a DNS datagram to feed into the program. Examples of a query and its response in raw form are provided in the
/data
folder - You can generate a query of your own by using netcat to listen on a port where no DNS server is listening, and then dig on that port.
nc -u -l 1053 > query.pkt
in one terminaldig +retry=0 -p 1053 @127.0.0.1 +noedns google.com
in another
- You can generate a response from this query by using netcat to redirect the query UDP datagram as input to a DNS resolver like Google's 8.8.8.8 and redirect the response to a capturing file.
nc -u 8.8.8.8 53 < query.pkt > response.pkt
- You can view the packet captures as hex if desired
hexdump -C response.pkt
- Tying it all together you can then invoke Crabby DNS
cargo run -- deserialize -f ./response.pkt
Example
$ nc -u -l 1053 > query.pkt &
[2] 28112
$ dig +retry=0 -p 1053 @127.0.0.1 +noedns google.com
; <<>> DiG 9.16.1-Ubuntu <<>> +retry -p 1053 @127.0.0.1 +noedns google.com
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
$ kill 28112
[2]- Terminated nc -u -l 1053 > query.pkt
$ nc -u 8.8.8.8 53 < query.pkt > response.pkt
^C
$ hexdump -C response.pkt
00000000 6e 04 81 80 00 01 00 01 00 00 00 00 06 67 6f 6f |n............goo|
00000010 67 6c 65 03 63 6f 6d 00 00 01 00 01 c0 0c 00 01 |gle.com.........|
00000020 00 01 00 00 00 15 00 04 ac d9 0c ae |............|
0000002c
$ cargo run -- deserialize -f ./response.pkt
#########################################
# DNS MESSAGE #
#########################################
Header {
id: 28164,
message_type: Response,
op_code: Query,
authoritative_answer: false,
truncation: false,
recursion_desired: true,
recursion_available: true,
authentic_data: false,
checking_disabled: false,
response_code: NoError,
question_count: 1,
answer_count: 1,
authority_count: 0,
additional_count: 0,
}
Question {
domain_name: DomainName(
"google.com",
),
qtype: RRType(
A,
),
qclass: RRClass(
IN,
),
}
ResourceRecord {
domain_name: DomainName(
"google.com",
),
rrtype: A,
rrclass: IN,
ttl: 21,
rrdata_len: 4,
rrdata: A(
172.217.12.174,
),
}
Dependencies
~1MB
~11K SLoC