mirror of
https://github.com/ivre/masscanned.git
synced 2025-10-15 04:58:21 +00:00
688 lines
27 KiB
Rust
688 lines
27 KiB
Rust
// This file is part of masscanned.
|
|
// Copyright 2022 - The IVRE project
|
|
//
|
|
// Masscanned is free software: you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Masscanned is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
// License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Masscanned. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
mod cst;
|
|
|
|
mod header;
|
|
use header::{DNSHeader, DNSHeaderState};
|
|
|
|
mod query;
|
|
use query::{DNSQuery, DNSQueryState};
|
|
|
|
mod rr;
|
|
use rr::{DNSRRState, DNSRR};
|
|
|
|
use crate::proto::dissector::{MPacket, PacketDissector};
|
|
use crate::proto::ClientInfo;
|
|
use crate::proto::TCPControlBlock;
|
|
use crate::Masscanned;
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
enum DNSState {
|
|
Header,
|
|
Query,
|
|
Answer,
|
|
Authority,
|
|
Additional,
|
|
End,
|
|
}
|
|
|
|
pub struct DNSPacket {
|
|
d: PacketDissector<DNSState>,
|
|
header: DNSHeader,
|
|
qd: Vec<DNSQuery>,
|
|
rr: Vec<DNSRR>,
|
|
ns: Vec<DNSRR>,
|
|
ar: Vec<DNSRR>,
|
|
}
|
|
|
|
impl TryFrom<Vec<u8>> for DNSPacket {
|
|
type Error = &'static str;
|
|
|
|
fn try_from(item: Vec<u8>) -> Result<Self, Self::Error> {
|
|
let mut dns = DNSPacket::new();
|
|
for b in item {
|
|
dns.parse(&b);
|
|
}
|
|
if dns.d.state == DNSState::End {
|
|
Ok(dns)
|
|
} else {
|
|
Err("packet is incomplete")
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&DNSPacket> for Vec<u8> {
|
|
fn from(item: &DNSPacket) -> Self {
|
|
let mut v = Vec::new();
|
|
v.extend(Vec::<u8>::from(&item.header));
|
|
for qd in &item.qd {
|
|
v.extend(Vec::<u8>::from(qd));
|
|
}
|
|
for rr in &item.rr {
|
|
v.extend(Vec::<u8>::from(rr));
|
|
}
|
|
for ns in &item.ns {
|
|
v.extend(Vec::<u8>::from(ns));
|
|
}
|
|
for ar in &item.ar {
|
|
v.extend(Vec::<u8>::from(ar));
|
|
}
|
|
v
|
|
}
|
|
}
|
|
|
|
impl MPacket for DNSPacket {
|
|
fn new() -> Self {
|
|
DNSPacket {
|
|
d: PacketDissector::new(DNSState::Header),
|
|
header: DNSHeader::new(),
|
|
qd: Vec::new(),
|
|
rr: Vec::new(),
|
|
ns: Vec::new(),
|
|
ar: Vec::new(),
|
|
}
|
|
}
|
|
|
|
fn parse(&mut self, byte: &u8) {
|
|
match self.d.state {
|
|
DNSState::Header => {
|
|
self.header.parse(byte);
|
|
if self.header.d.state == DNSHeaderState::End {
|
|
if self.header.qdcount > 0 {
|
|
self.qd.push(DNSQuery::new());
|
|
self.d.next_state(DNSState::Query);
|
|
} else if self.header.ancount > 0 {
|
|
self.rr.push(DNSRR::new());
|
|
self.d.next_state(DNSState::Answer);
|
|
} else if self.header.nscount > 0 {
|
|
self.d.next_state(DNSState::Authority);
|
|
} else if self.header.arcount > 0 {
|
|
self.d.next_state(DNSState::Additional);
|
|
} else {
|
|
self.d.next_state(DNSState::End);
|
|
}
|
|
}
|
|
}
|
|
DNSState::Query => {
|
|
let qdcount = self.qd.len();
|
|
self.qd[qdcount - 1].parse(byte);
|
|
if self.qd[qdcount - 1].d.state == DNSQueryState::End {
|
|
if self.header.qdcount as usize > self.qd.len() {
|
|
self.qd.push(DNSQuery::new());
|
|
} else if self.header.ancount > 0 {
|
|
self.rr.push(DNSRR::new());
|
|
self.d.next_state(DNSState::Answer);
|
|
} else if self.header.nscount > 0 {
|
|
self.d.next_state(DNSState::Authority);
|
|
} else if self.header.arcount > 0 {
|
|
self.d.next_state(DNSState::Additional);
|
|
} else {
|
|
self.d.next_state(DNSState::End);
|
|
}
|
|
}
|
|
}
|
|
DNSState::Answer => {
|
|
let ancount = self.rr.len();
|
|
self.rr[ancount - 1].parse(byte);
|
|
if self.rr[ancount - 1].d.state == DNSRRState::End {
|
|
if self.header.ancount as usize > self.rr.len() {
|
|
self.rr.push(DNSRR::new());
|
|
} else if self.header.nscount > 0 {
|
|
self.d.next_state(DNSState::Authority);
|
|
} else if self.header.arcount > 0 {
|
|
self.d.next_state(DNSState::Additional);
|
|
} else {
|
|
self.d.next_state(DNSState::End);
|
|
}
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
fn repl(
|
|
&self,
|
|
masscanned: &Masscanned,
|
|
client_info: &ClientInfo,
|
|
_tcb: Option<&mut TCPControlBlock>,
|
|
) -> Option<Vec<u8>> {
|
|
let mut ans = DNSPacket::new();
|
|
ans.header = if let Some(hdr) = self.header.repl(&masscanned, &client_info, None) {
|
|
if let Ok(h) = DNSHeader::try_from(hdr) {
|
|
h
|
|
} else {
|
|
return None;
|
|
}
|
|
} else {
|
|
return None;
|
|
};
|
|
/* reply to qd */
|
|
for qd in &self.qd {
|
|
if let Ok(q) = DNSQuery::try_from(Vec::<u8>::from(qd)) {
|
|
ans.qd.push(q);
|
|
} else {
|
|
return None;
|
|
}
|
|
if let Some(raw_rr) = qd.repl(&masscanned, &client_info, None) {
|
|
if let Ok(rr) = DNSRR::try_from(raw_rr) {
|
|
ans.rr.push(rr);
|
|
} else {
|
|
return None;
|
|
}
|
|
} else {
|
|
return None;
|
|
}
|
|
}
|
|
Some(Vec::<u8>::from(&ans))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::cst::{DNSClass, DNSType};
|
|
use super::*;
|
|
|
|
use pnet::util::MacAddr;
|
|
use std::net::{IpAddr, Ipv4Addr};
|
|
use std::str::FromStr;
|
|
|
|
use crate::logger::MetaLogger;
|
|
|
|
#[test]
|
|
fn parse_qd_all() {
|
|
/* OK */
|
|
/* scapy: DNS(id=0x1337,
|
|
* qd=DNSQR(qname="www.example1.com")/DNSQR(qname="www.example2.com")/DNSQR(qname="www.example3.com"))
|
|
**/
|
|
let payload = b"\x137\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x03www\x08example3\x03com\x00\x00\x01\x00\x01";
|
|
let dns = match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_dns) => _dns,
|
|
Err(e) => panic!("error while parsing DNS packet: {}", e),
|
|
};
|
|
assert!(dns.header.id == 0x1337);
|
|
assert!(dns.header._qr == false);
|
|
assert!(dns.header._opcode == 0);
|
|
assert!(dns.header._aa == false);
|
|
assert!(dns.header._tc == false);
|
|
assert!(dns.header._rd == true);
|
|
assert!(dns.header._ra == false);
|
|
assert!(dns.header._z == 0);
|
|
assert!(dns.header._rcode == 0);
|
|
assert!(dns.header.qdcount == 3);
|
|
assert!(dns.header.ancount == 0);
|
|
assert!(dns.header.nscount == 0);
|
|
assert!(dns.header.arcount == 0);
|
|
assert!(dns.qd.len() == 3);
|
|
assert!(
|
|
dns.qd[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[0].type_ == DNSType::A);
|
|
assert!(dns.qd[0].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[1].type_ == DNSType::A);
|
|
assert!(dns.qd[1].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[2].type_ == DNSType::A);
|
|
assert!(dns.qd[2].class == DNSClass::IN);
|
|
/* KO */
|
|
let payload = b"\x137\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x03www\x08example3\x03com\x00\x00\x01\x00";
|
|
match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_) => panic!("parsing should have failed"),
|
|
Err(_) => {}
|
|
}
|
|
let payload = b"xxx";
|
|
match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_) => panic!("parsing should have failed"),
|
|
Err(_) => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn parse_qd_byte_by_byte() {
|
|
/* scapy: DNS(id=0x1337,
|
|
* qd=DNSQR(qname="www.example1.com")/DNSQR(qname="www.example2.com")/DNSQR(qname="www.example3.com"))
|
|
**/
|
|
let payload = b"\x137\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x03www\x08example3\x03com\x00\x00\x01\x00\x01";
|
|
let mut dns = DNSPacket::new();
|
|
for b in payload {
|
|
assert!(dns.d.state != DNSState::End);
|
|
dns.parse(&b);
|
|
}
|
|
assert!(dns.d.state == DNSState::End);
|
|
assert!(dns.header.id == 0x1337);
|
|
assert!(dns.header._qr == false);
|
|
assert!(dns.header._opcode == 0);
|
|
assert!(dns.header._aa == false);
|
|
assert!(dns.header._tc == false);
|
|
assert!(dns.header._rd == true);
|
|
assert!(dns.header._ra == false);
|
|
assert!(dns.header._z == 0);
|
|
assert!(dns.header._rcode == 0);
|
|
assert!(dns.header.qdcount == 3);
|
|
assert!(dns.header.ancount == 0);
|
|
assert!(dns.header.nscount == 0);
|
|
assert!(dns.header.arcount == 0);
|
|
assert!(dns.qd.len() == 3);
|
|
assert!(
|
|
dns.qd[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[0].type_ == DNSType::A);
|
|
assert!(dns.qd[0].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[1].type_ == DNSType::A);
|
|
assert!(dns.qd[1].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[2].type_ == DNSType::A);
|
|
assert!(dns.qd[2].class == DNSClass::IN);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_rr_all() {
|
|
/* OK */
|
|
/* scapy: DNS(id=1234, qr=True, aa=True, qd=None,
|
|
* an=DNSRR(rrname="www.example1.com", rdata="127.0.0.1")/DNSRR(rrname="www.example2.com", rdata="127.0.0.2")/DNSRR(rrname="www.example3.com", rdata="127.0.0.3"))
|
|
**/
|
|
let payload = b"\x04\xd2\x85\x00\x00\x00\x00\x03\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x02\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x03";
|
|
let dns = match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_dns) => _dns,
|
|
Err(e) => panic!("error while parsing DNS packet: {}", e),
|
|
};
|
|
assert!(dns.header.id == 1234);
|
|
assert!(dns.header._qr == true);
|
|
assert!(dns.header._opcode == 0);
|
|
assert!(dns.header._aa == true);
|
|
assert!(dns.header._tc == false);
|
|
assert!(dns.header._rd == true);
|
|
assert!(dns.header._ra == false);
|
|
assert!(dns.header._z == 0);
|
|
assert!(dns.header._rcode == 0);
|
|
assert!(dns.header.qdcount == 0);
|
|
assert!(dns.header.ancount == 3);
|
|
assert!(dns.header.nscount == 0);
|
|
assert!(dns.header.arcount == 0);
|
|
assert!(dns.rr.len() == 3);
|
|
assert!(
|
|
dns.rr[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[0].type_ == DNSType::A);
|
|
assert!(dns.rr[0].class == DNSClass::IN);
|
|
assert!(dns.rr[0].rdata == [0x7f, 0x00, 0x00, 0x01]);
|
|
assert!(
|
|
dns.rr[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[1].type_ == DNSType::A);
|
|
assert!(dns.rr[1].class == DNSClass::IN);
|
|
assert!(dns.rr[1].rdata == [0x7f, 0x00, 0x00, 0x02]);
|
|
assert!(
|
|
dns.rr[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[2].type_ == DNSType::A);
|
|
assert!(dns.rr[2].class == DNSClass::IN);
|
|
assert!(dns.rr[2].rdata == [0x7f, 0x00, 0x00, 0x03]);
|
|
/* KO */
|
|
let payload = b"\x04\xd2\x85\x00\x00\x00\x00\x04\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x02\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x03";
|
|
match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_) => panic!("parsing should have failed"),
|
|
Err(_) => {}
|
|
}
|
|
let payload = b"xxx";
|
|
match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_) => panic!("parsing should have failed"),
|
|
Err(_) => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn parse_rr_byte_by_byte() {
|
|
/* scapy: DNS(id=1234, qr=True, aa=True, qd=None,
|
|
* an=DNSRR(rrname="www.example1.com", rdata="127.0.0.1")/DNSRR(rrname="www.example2.com", rdata="127.0.0.2")/DNSRR(rrname="www.example3.com", rdata="127.0.0.3"))
|
|
**/
|
|
let payload = b"\x04\xd2\x85\x00\x00\x00\x00\x03\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x02\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x03";
|
|
let mut dns = DNSPacket::new();
|
|
for b in payload {
|
|
assert!(dns.d.state != DNSState::End);
|
|
dns.parse(&b);
|
|
}
|
|
assert!(dns.d.state == DNSState::End);
|
|
assert!(dns.header.id == 1234);
|
|
assert!(dns.header._qr == true);
|
|
assert!(dns.header._opcode == 0);
|
|
assert!(dns.header._aa == true);
|
|
assert!(dns.header._tc == false);
|
|
assert!(dns.header._rd == true);
|
|
assert!(dns.header._ra == false);
|
|
assert!(dns.header._z == 0);
|
|
assert!(dns.header._rcode == 0);
|
|
assert!(dns.header.qdcount == 0);
|
|
assert!(dns.header.ancount == 3);
|
|
assert!(dns.header.nscount == 0);
|
|
assert!(dns.header.arcount == 0);
|
|
assert!(dns.rr.len() == 3);
|
|
assert!(
|
|
dns.rr[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[0].type_ == DNSType::A);
|
|
assert!(dns.rr[0].class == DNSClass::IN);
|
|
assert!(dns.rr[0].rdata == [0x7f, 0x00, 0x00, 0x01]);
|
|
assert!(
|
|
dns.rr[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[1].type_ == DNSType::A);
|
|
assert!(dns.rr[1].class == DNSClass::IN);
|
|
assert!(dns.rr[1].rdata == [0x7f, 0x00, 0x00, 0x02]);
|
|
assert!(
|
|
dns.rr[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[2].type_ == DNSType::A);
|
|
assert!(dns.rr[2].class == DNSClass::IN);
|
|
assert!(dns.rr[2].rdata == [0x7f, 0x00, 0x00, 0x03]);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_qd_rr_all() {
|
|
/* scapy: DNS(id=1234, qr=True, aa=True,
|
|
* qd=DNSQR(qname="www.example1.com")/DNSQR(qname="www.example2.com")/DNSQR(qname="www.example3.com"),
|
|
* an=DNSRR(rrname="www.example1.com", rdata="127.0.0.1")/DNSRR(rrname="www.example2.com", rdata="127.0.0.2")/DNSRR(rrname="www.example3.com", rdata="127.0.0.3"))
|
|
*/
|
|
let payload = b"\x04\xd2\x85\x00\x00\x03\x00\x03\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x02\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x03";
|
|
let dns = match DNSPacket::try_from(payload.to_vec()) {
|
|
Ok(_dns) => _dns,
|
|
Err(e) => panic!("error while parsing DNS packet: {}", e),
|
|
};
|
|
assert!(dns.header.id == 1234);
|
|
assert!(dns.header._qr == true);
|
|
assert!(dns.header._opcode == 0);
|
|
assert!(dns.header._aa == true);
|
|
assert!(dns.header._tc == false);
|
|
assert!(dns.header._rd == true);
|
|
assert!(dns.header._ra == false);
|
|
assert!(dns.header._z == 0);
|
|
assert!(dns.header._rcode == 0);
|
|
assert!(dns.header.qdcount == 3);
|
|
assert!(dns.header.ancount == 3);
|
|
assert!(dns.header.nscount == 0);
|
|
assert!(dns.header.arcount == 0);
|
|
assert!(dns.qd.len() == 3);
|
|
assert!(
|
|
dns.qd[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[0].type_ == DNSType::A);
|
|
assert!(dns.qd[0].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[1].type_ == DNSType::A);
|
|
assert!(dns.qd[1].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[2].type_ == DNSType::A);
|
|
assert!(dns.qd[2].class == DNSClass::IN);
|
|
assert!(dns.rr.len() == 3);
|
|
assert!(
|
|
dns.rr[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[0].type_ == DNSType::A);
|
|
assert!(dns.rr[0].class == DNSClass::IN);
|
|
assert!(dns.rr[0].rdata == [0x7f, 0x00, 0x00, 0x01]);
|
|
assert!(
|
|
dns.rr[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[1].type_ == DNSType::A);
|
|
assert!(dns.rr[1].class == DNSClass::IN);
|
|
assert!(dns.rr[1].rdata == [0x7f, 0x00, 0x00, 0x02]);
|
|
assert!(
|
|
dns.rr[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[2].type_ == DNSType::A);
|
|
assert!(dns.rr[2].class == DNSClass::IN);
|
|
assert!(dns.rr[2].rdata == [0x7f, 0x00, 0x00, 0x03]);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_qr_rr_byte_by_byte() {
|
|
/* scapy: DNS(id=1234, qr=True, aa=True,
|
|
* qd=DNSQR(qname="www.example1.com")/DNSQR(qname="www.example2.com")/DNSQR(qname="www.example3.com"),
|
|
* an=DNSRR(rrname="www.example1.com", rdata="127.0.0.1")/DNSRR(rrname="www.example2.com", rdata="127.0.0.2")/DNSRR(rrname="www.example3.com", rdata="127.0.0.3"))
|
|
*/
|
|
let payload = b"\x04\xd2\x85\x00\x00\x03\x00\x03\x00\x00\x00\x00\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x03www\x08example1\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x01\x03www\x08example2\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x02\x03www\x08example3\x03com\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x7f\x00\x00\x03";
|
|
let mut dns = DNSPacket::new();
|
|
for b in payload {
|
|
assert!(dns.d.state != DNSState::End);
|
|
dns.parse(&b);
|
|
}
|
|
assert!(dns.d.state == DNSState::End);
|
|
assert!(dns.header.id == 1234);
|
|
assert!(dns.header._qr == true);
|
|
assert!(dns.header._opcode == 0);
|
|
assert!(dns.header._aa == true);
|
|
assert!(dns.header._tc == false);
|
|
assert!(dns.header._rd == true);
|
|
assert!(dns.header._ra == false);
|
|
assert!(dns.header._z == 0);
|
|
assert!(dns.header._rcode == 0);
|
|
assert!(dns.header.qdcount == 3);
|
|
assert!(dns.header.ancount == 3);
|
|
assert!(dns.header.nscount == 0);
|
|
assert!(dns.header.arcount == 0);
|
|
assert!(dns.qd.len() == 3);
|
|
assert!(
|
|
dns.qd[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[0].type_ == DNSType::A);
|
|
assert!(dns.qd[0].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[1].type_ == DNSType::A);
|
|
assert!(dns.qd[1].class == DNSClass::IN);
|
|
assert!(
|
|
dns.qd[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.qd[2].type_ == DNSType::A);
|
|
assert!(dns.qd[2].class == DNSClass::IN);
|
|
assert!(dns.rr.len() == 3);
|
|
assert!(
|
|
dns.rr[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x31,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[0].type_ == DNSType::A);
|
|
assert!(dns.rr[0].class == DNSClass::IN);
|
|
assert!(dns.rr[0].rdata == [0x7f, 0x00, 0x00, 0x01]);
|
|
assert!(
|
|
dns.rr[1].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x32,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[1].type_ == DNSType::A);
|
|
assert!(dns.rr[1].class == DNSClass::IN);
|
|
assert!(dns.rr[1].rdata == [0x7f, 0x00, 0x00, 0x02]);
|
|
assert!(
|
|
dns.rr[2].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x08, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x33,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(dns.rr[2].type_ == DNSType::A);
|
|
assert!(dns.rr[2].class == DNSClass::IN);
|
|
assert!(dns.rr[2].rdata == [0x7f, 0x00, 0x00, 0x03]);
|
|
}
|
|
|
|
#[test]
|
|
fn reply_in_a() {
|
|
let masscanned = Masscanned {
|
|
synack_key: [0, 0],
|
|
mac: MacAddr::from_str("00:00:00:00:00:00").expect("error parsing default MAC address"),
|
|
iface: None,
|
|
self_ip_list: None,
|
|
remote_ip_deny_list: None,
|
|
log: MetaLogger::new(),
|
|
};
|
|
let mut client_info = ClientInfo::new();
|
|
/* scapy: DNS(id=0x1337,
|
|
* qd=DNSQR(qname="www.example.com"))
|
|
**/
|
|
let payload = b"\x137\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x07example\x03com\x00\x00\x01\x00\x01";
|
|
let dns = DNSPacket::try_from(payload.to_vec()).unwrap();
|
|
for ip in [
|
|
Ipv4Addr::new(127, 0, 0, 1),
|
|
Ipv4Addr::new(0, 0, 0, 0),
|
|
Ipv4Addr::new(4, 3, 2, 1),
|
|
] {
|
|
client_info.ip.dst = Some(IpAddr::V4(ip));
|
|
let ans = if let Some(a) = dns.repl(&masscanned, &client_info, None) {
|
|
DNSPacket::try_from(a).unwrap()
|
|
} else {
|
|
panic!("expected a reply, got None");
|
|
};
|
|
assert!(ans.header.id == 0x1337);
|
|
assert!(ans.header._qr == true);
|
|
assert!(ans.header._opcode == 0);
|
|
assert!(ans.header._aa == true);
|
|
assert!(ans.header._tc == false);
|
|
assert!(ans.header._rd == dns.header._rd);
|
|
assert!(ans.header._ra == false);
|
|
assert!(ans.header._z == 0);
|
|
assert!(ans.header._rcode == 0);
|
|
assert!(ans.header.qdcount == 1);
|
|
assert!(ans.header.ancount == 1);
|
|
assert!(ans.header.nscount == 0);
|
|
assert!(ans.header.arcount == 0);
|
|
assert!(ans.qd.len() == 1);
|
|
assert!(
|
|
ans.qd[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(ans.qd[0].type_ == DNSType::A);
|
|
assert!(ans.qd[0].class == DNSClass::IN);
|
|
assert!(ans.rr.len() == 1);
|
|
assert!(
|
|
ans.rr[0].name
|
|
== [
|
|
0x03, 0x77, 0x77, 0x77, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
|
|
0x03, 0x63, 0x6f, 0x6d, 0x00
|
|
]
|
|
);
|
|
assert!(ans.rr[0].type_ == DNSType::A);
|
|
assert!(ans.rr[0].class == DNSClass::IN);
|
|
assert!(ans.rr[0].rdata == ip.octets());
|
|
}
|
|
}
|
|
}
|