Backed out 14 changesets (bug 1554976) for Windows build bustages on a CLOSED TREE.

Backed out changeset a9b209d9d880 (bug 1554976)
Backed out changeset 27b4dddf9597 (bug 1554976)
Backed out changeset 3e16c10bb966 (bug 1554976)
Backed out changeset 6a404fca61dc (bug 1554976)
Backed out changeset 77c4e76c8130 (bug 1554976)
Backed out changeset 24f146b86cc4 (bug 1554976)
Backed out changeset b49b4326dcfd (bug 1554976)
Backed out changeset e2c837d1e0a0 (bug 1554976)
Backed out changeset 24728144c263 (bug 1554976)
Backed out changeset a099e69241a0 (bug 1554976)
Backed out changeset 0e34595c2680 (bug 1554976)
Backed out changeset a506bb40047e (bug 1554976)
Backed out changeset 513026415092 (bug 1554976)
Backed out changeset e0fc6a1d4332 (bug 1554976)
This commit is contained in:
Gurzau Raul 2019-08-28 18:10:11 +03:00
parent 71c23d8716
commit a6c5c5e3ac
77 changed files with 80 additions and 3646 deletions

23
Cargo.lock generated
View File

@ -954,15 +954,6 @@ dependencies = [
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
]
[[package]]
name = "dns-parser"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dogear"
version = "0.3.3"
@ -1286,7 +1277,6 @@ dependencies = [
"kvstore 0.1.0",
"lmdb-rkv-sys 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mdns_service 0.1.0",
"mozurl 0.0.1",
"mp4parse_capi 0.11.2",
"netwerk_helper 0.0.1",
@ -1745,18 +1735,6 @@ name = "matches"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mdns_service"
version = "0.1.0"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"socket2 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "1.0.2"
@ -3969,7 +3947,6 @@ dependencies = [
"checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"
"checksum dogear 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57cd6ee785daa898686f3e2fb4a2b1ce490fcd6d69665c857d16fb61b48f4aae"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"

View File

@ -1652,6 +1652,14 @@ PeerConnectionWrapper.prototype = {
"usernameFragment not empty"
);
// only check the m-section for the updated default addr that corresponds
// with this candidate.
var mSections = this.localDescription.sdp.split("\r\nm=");
sdputils.checkSdpCLineNotDefault(
mSections[anEvent.candidate.sdpMLineIndex + 1],
this.label
);
ok(
typeof anEvent.candidate.sdpMLineIndex === "number",
"SDP MLine Index needs to exist"

View File

@ -104,6 +104,7 @@ var sdputils = {
msection.includes("a=end-of-candidates"),
label + ": SDP contains end-of-candidates"
);
sdputils.checkSdpCLineNotDefault(msection, label);
if (!msection.startsWith("m=application")) {
if (testOptions.rtcpmux) {
@ -153,6 +154,16 @@ var sdputils = {
}
},
// takes sdp in string form (or possibly a fragment, say an m-section), and
// verifies that the default 0.0.0.0 addr is not present.
checkSdpCLineNotDefault: function(sdpStr, label) {
info("CLINE-NO-DEFAULT-ADDR-SDP: " + JSON.stringify(sdpStr));
ok(
!sdpStr.includes("c=IN IP4 0.0.0.0"),
label + ": SDP contains non-zero IP c line"
);
},
// Note, we don't bother removing the fmtp lines, which makes a good test
// for some SDP parsing issues.
removeCodec: function(sdp, codec) {

View File

@ -20,7 +20,6 @@ if (!("mediaDevices" in navigator)) {
} else {
runNetworkTest(async (options = {}) => {
await pushPrefs(
['media.peerconnection.ice.obfuscate_host_addresses', false],
['media.peerconnection.nat_simulator.filtering_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.mapping_type', 'PORT_DEPENDENT'],
['media.getusermedia.insecure.enabled', true]);

View File

@ -19,7 +19,6 @@ if (!("mediaDevices" in navigator)) {
} else {
runNetworkTest(async (options = {}) => {
await pushPrefs(
['media.peerconnection.ice.obfuscate_host_addresses', false],
['media.peerconnection.nat_simulator.filtering_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.mapping_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.block_udp', true],

View File

@ -19,7 +19,6 @@ if (!("mediaDevices" in navigator)) {
} else {
runNetworkTest(async (options = {}) => {
await pushPrefs(
['media.peerconnection.ice.obfuscate_host_addresses', false],
['media.peerconnection.nat_simulator.filtering_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.mapping_type', 'PORT_DEPENDENT'],
['media.peerconnection.nat_simulator.block_udp', true],

View File

@ -20,7 +20,6 @@ if (!("mediaDevices" in navigator)) {
} else {
runNetworkTest(async (options = {}) => {
await pushPrefs(
['media.peerconnection.ice.obfuscate_host_addresses', false],
['media.peerconnection.nat_simulator.filtering_type', 'ENDPOINT_INDEPENDENT'],
['media.peerconnection.nat_simulator.mapping_type', 'ENDPOINT_INDEPENDENT'],
['media.getusermedia.insecure.enabled', true]);

View File

@ -33,8 +33,7 @@ class MediaTransportParent : public dom::PMediaTransportParent {
mozilla::ipc::IPCResult RecvSetTargetForDefaultLocalAddressLookup(
const string& targetIp, uint16_t targetPort);
mozilla::ipc::IPCResult RecvStartIceGathering(
const bool& defaultRouteOnly, const bool& obfuscateAddresses,
const net::NrIceStunAddrArray& stunAddrs);
const bool& defaultRouteOnly, const net::NrIceStunAddrArray& stunAddrs);
mozilla::ipc::IPCResult RecvActivateTransport(
const string& transportId, const string& localUfrag,
const string& localPwd, const int& componentCount,

View File

@ -59,7 +59,6 @@ parent:
uint16_t targetPort);
async StartIceGathering(bool defaultRouteOnly,
bool obfuscateHostAddresses,
NrIceStunAddrArray stunAddrs);
async ActivateTransport(string transportId,

View File

@ -158,8 +158,7 @@ DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::RTCIceServer, mCredential,
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::CandidateInfo, mCandidate, mUfrag,
mDefaultHostRtp, mDefaultPortRtp,
mDefaultHostRtcp, mDefaultPortRtcp,
mMDNSAddress, mActualAddress)
mDefaultHostRtcp, mDefaultPortRtcp)
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::DtlsDigest, algorithm_, value_)

View File

@ -18,9 +18,6 @@ async protocol PStunAddrsRequest
parent:
async GetStunAddrs();
async RegisterMDNSHostname(nsCString hostname, nsCString address);
async UnregisterMDNSHostname(nsCString hostname);
async __delete__();
child:

View File

@ -11,12 +11,6 @@
#include "mtransport/nricemediastream.h" // needed only for including nricectx.h
#include "mtransport/nricestunaddr.h"
#include "../mdns_service/mdns_service.h"
extern "C" {
#include "local_addr.h"
}
using namespace mozilla::ipc;
namespace mozilla {
@ -30,14 +24,6 @@ StunAddrsRequestParent::StunAddrsRequestParent() : mIPCClosed(false) {
MOZ_ASSERT(mSTSThread);
}
StunAddrsRequestParent::~StunAddrsRequestParent() {
ASSERT_ON_THREAD(mMainThread);
if (mSharedMDNSService) {
mSharedMDNSService = nullptr;
}
}
mozilla::ipc::IPCResult StunAddrsRequestParent::RecvGetStunAddrs() {
ASSERT_ON_THREAD(mMainThread);
@ -53,33 +39,6 @@ mozilla::ipc::IPCResult StunAddrsRequestParent::RecvGetStunAddrs() {
return IPC_OK();
}
mozilla::ipc::IPCResult StunAddrsRequestParent::RecvRegisterMDNSHostname(
const nsCString& aHostname, const nsCString& aAddress) {
ASSERT_ON_THREAD(mMainThread);
if (mIPCClosed) {
return IPC_OK();
}
mSharedMDNSService->RegisterHostname(aHostname.BeginReading(),
aAddress.BeginReading());
return IPC_OK();
}
mozilla::ipc::IPCResult StunAddrsRequestParent::RecvUnregisterMDNSHostname(
const nsCString& aHostname) {
ASSERT_ON_THREAD(mMainThread);
if (mIPCClosed) {
return IPC_OK();
}
mSharedMDNSService->UnregisterHostname(aHostname.BeginReading());
return IPC_OK();
}
mozilla::ipc::IPCResult StunAddrsRequestParent::Recv__delete__() {
// see note below in ActorDestroy
mIPCClosed = true;
@ -120,71 +79,13 @@ void StunAddrsRequestParent::SendStunAddrs_m(const NrIceStunAddrArray& addrs) {
return;
}
// This means that the mDNS service will continue running until shutdown
// once started. The StunAddrsRequestParent destructor does not run until
// shutdown anyway (see Bug 1569311), so there is not much we can do about
// this here. One option would be to add a check if there are no hostnames
// registered after UnregisterHostname is called, and if so, stop the mDNS
// service at that time (see Bug 1569955.)
if (!mSharedMDNSService) {
for (auto& addr : addrs) {
nr_transport_addr* local_addr =
const_cast<nr_transport_addr*>(&addr.localAddr().addr);
if (addr.localAddr().addr.ip_version == NR_IPV4 &&
!nr_transport_addr_is_loopback(local_addr)) {
char addrstring[16];
nr_transport_addr_get_addrstring(local_addr, addrstring, 16);
mSharedMDNSService = new MDNSServiceWrapper(addrstring);
break;
}
}
}
mIPCClosed = true;
// send the new addresses back to the child
Unused << SendOnStunAddrsAvailable(addrs);
}
StaticRefPtr<StunAddrsRequestParent::MDNSServiceWrapper>
StunAddrsRequestParent::mSharedMDNSService;
NS_IMPL_ADDREF(StunAddrsRequestParent)
NS_IMPL_RELEASE(StunAddrsRequestParent)
StunAddrsRequestParent::MDNSServiceWrapper::MDNSServiceWrapper(
const std::string& ifaddr)
: ifaddr(ifaddr) {}
void StunAddrsRequestParent::MDNSServiceWrapper::RegisterHostname(
const char* hostname, const char* address) {
StartIfRequired();
if (mMDNSService) {
mdns_service_register_hostname(mMDNSService, hostname, address);
}
}
void StunAddrsRequestParent::MDNSServiceWrapper::UnregisterHostname(
const char* hostname) {
StartIfRequired();
if (mMDNSService) {
mdns_service_unregister_hostname(mMDNSService, hostname);
}
}
StunAddrsRequestParent::MDNSServiceWrapper::~MDNSServiceWrapper() {
if (mMDNSService) {
mdns_service_stop(mMDNSService);
mMDNSService = nullptr;
}
}
void StunAddrsRequestParent::MDNSServiceWrapper::StartIfRequired() {
if (!mMDNSService) {
mMDNSService = mdns_service_start(ifaddr.c_str());
}
}
NS_IMPL_ADDREF(StunAddrsRequestParent::MDNSServiceWrapper)
NS_IMPL_RELEASE(StunAddrsRequestParent::MDNSServiceWrapper)
} // namespace net
} // namespace mozilla

View File

@ -7,11 +7,6 @@
#include "mozilla/net/PStunAddrsRequestParent.h"
#include "nsICancelable.h"
#include "nsIDNSServiceDiscovery.h"
struct MDNSService;
namespace mozilla {
namespace net {
@ -27,13 +22,9 @@ class StunAddrsRequestParent : public PStunAddrsRequestParent {
mozilla::ipc::IPCResult Recv__delete__() override;
protected:
virtual ~StunAddrsRequestParent();
virtual ~StunAddrsRequestParent() {}
virtual mozilla::ipc::IPCResult RecvGetStunAddrs() override;
virtual mozilla::ipc::IPCResult RecvRegisterMDNSHostname(
const nsCString& hostname, const nsCString& address) override;
virtual mozilla::ipc::IPCResult RecvUnregisterMDNSHostname(
const nsCString& hostname) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
nsCOMPtr<nsIThread> mMainThread;
@ -47,29 +38,6 @@ class StunAddrsRequestParent : public PStunAddrsRequestParent {
private:
bool mIPCClosed; // true if IPDL channel has been closed (child crash)
class MDNSServiceWrapper {
public:
explicit MDNSServiceWrapper(const std::string& ifaddr);
void RegisterHostname(const char* hostname, const char* address);
void UnregisterHostname(const char* hostname);
NS_IMETHOD_(MozExternalRefCountType) AddRef();
NS_IMETHOD_(MozExternalRefCountType) Release();
protected:
ThreadSafeAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
private:
virtual ~MDNSServiceWrapper();
void StartIfRequired();
std::string ifaddr;
MDNSService* mMDNSService = nullptr;
};
static StaticRefPtr<MDNSServiceWrapper> mSharedMDNSService;
};
} // namespace net

View File

@ -38,21 +38,7 @@ include("/ipc/chromium/chromium-config.mozbuild")
FINAL_LIBRARY = 'xul'
DEFINES['R_DEFINED_INT2'] = 'int16_t'
DEFINES['R_DEFINED_UINT2'] = 'uint16_t'
DEFINES['R_DEFINED_INT4'] = 'int32_t'
DEFINES['R_DEFINED_UINT4'] = 'uint32_t'
# These are defined to avoid a conflict between typedefs in winsock2.h and
# r_types.h. This is safe because these types are unused by the code here,
# but still deeply unfortunate. There is similar code in the win32 version of
# csi_platform.h, but that trick does not work here, even if that file is
# directly included.
DEFINES['R_DEFINED_INT8'] = 'int8_t'
DEFINES['R_DEFINED_UINT8'] = 'uint8_t'
LOCAL_INCLUDES += [
'/media/mtransport/third_party/nICEr/src/net',
'/media/mtransport/third_party/nrappkit/src/util/libekr',
'/media/webrtc',
'/media/webrtc/signaling/src/peerconnection',
'/netwerk/base',

View File

@ -1,13 +0,0 @@
[package]
name = "mdns_service"
version = "0.1.0"
authors = ["Dan Minor <dminor@mozilla.com>"]
edition = "2018"
[dependencies]
byteorder = "1.3.1"
dns-parser = "0.8.0"
log = "0.4"
mio = "0.6"
socket2 = { version = "0.3.9", features = ["reuseport"] }
uuid = { version = "0.7", features = ["v4"] }

View File

@ -1,23 +0,0 @@
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <new>
struct MDNSService;
extern "C" {
void mdns_service_register_hostname(MDNSService* serv, const char* hostname,
const char* addr);
MDNSService* mdns_service_start(const char* ifaddr);
void mdns_service_stop(MDNSService* serv);
void mdns_service_unregister_hostname(MDNSService* serv, const char* hostname);
const char* mdns_service_generate_uuid();
void mdns_service_free_uuid(const char* uuid);
} // extern "C"

View File

@ -1,312 +0,0 @@
/* -*- Mode: rust; rust-indent-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use byteorder::{BigEndian, WriteBytesExt};
use socket2::{Domain, Socket, Type};
use std::collections::HashMap;
use std::ffi::CStr;
use std::ffi::CString;
use std::io;
use std::net;
use std::os::raw::c_char;
use std::sync::mpsc::channel;
use std::thread;
use std::time;
use uuid::Uuid;
#[macro_use]
extern crate log;
// This code is derived from code for creating questions in the dns-parser
// crate. It would be nice to upstream this, or something similar.
fn create_answer(id: u16, answers: &Vec<(String, &[u8])>) -> Result<Vec<u8>, &'static str> {
let mut buf = Vec::with_capacity(512);
let head = dns_parser::Header {
id: id,
query: false,
opcode: dns_parser::Opcode::StandardQuery,
authoritative: true,
truncated: false,
recursion_desired: false,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: dns_parser::ResponseCode::NoError,
questions: 0,
answers: answers.len() as u16,
nameservers: 0,
additional: 0,
};
buf.extend([0u8; 12].iter());
head.write(&mut buf[..12]);
for (name, addr) in answers {
for part in name.split('.') {
if part.len() > 62 {
return Err("Name part length too long");
}
let ln = part.len() as u8;
buf.push(ln);
buf.extend(part.as_bytes());
}
buf.push(0);
if addr.len() == 4 {
buf.write_u16::<BigEndian>(dns_parser::Type::A as u16)
.unwrap();
} else {
buf.write_u16::<BigEndian>(dns_parser::Type::AAAA as u16)
.unwrap();
}
// set cache flush bit
buf.write_u16::<BigEndian>(dns_parser::Class::IN as u16 | (0x1 << 15))
.unwrap();
buf.write_u32::<BigEndian>(120).unwrap();
buf.write_u16::<BigEndian>(addr.len() as u16).unwrap();
buf.extend(*addr);
}
Ok(buf)
}
enum ServiceControl {
Register { hostname: String, address: String },
Unregister { hostname: String },
Stop,
}
pub struct MDNSService {
sender: Option<std::sync::mpsc::Sender<ServiceControl>>,
}
impl MDNSService {
fn register_hostname(&mut self, hostname: &str, address: &str) {
if let Some(sender) = &self.sender {
if let Err(err) = sender.send(ServiceControl::Register {
hostname: hostname.to_string(),
address: address.to_string(),
}) {
warn!(
"Could not send register hostname {} message: {}",
hostname, err
);
}
}
}
fn unregister_hostname(&mut self, hostname: &str) {
if let Some(sender) = &self.sender {
if let Err(err) = sender.send(ServiceControl::Unregister {
hostname: hostname.to_string(),
}) {
warn!(
"Could not send unregister hostname {} message: {}",
hostname, err
);
}
}
}
fn start(&mut self, addr: std::net::Ipv4Addr) -> io::Result<()> {
let (sender, receiver) = channel();
self.sender = Some(sender);
let port = 5353;
let socket = Socket::new(Domain::ipv4(), Type::dgram(), None).unwrap();
socket.set_reuse_address(true)?;
#[cfg(not(target_os = "windows"))]
socket.set_reuse_port(true)?;
socket.bind(&socket2::SockAddr::from(std::net::SocketAddr::from((
[0, 0, 0, 0],
port,
))))?;
let socket = socket.into_udp_socket();
socket.set_multicast_loop_v4(true)?;
socket.set_read_timeout(Some(time::Duration::from_millis(10)))?;
socket.join_multicast_v4(&std::net::Ipv4Addr::new(224, 0, 0, 251), &addr)?;
let builder = thread::Builder::new().name("mdns_service".to_string());
builder.spawn(move || {
let mdns_addr = std::net::SocketAddr::from(([224, 0, 0, 251], port));
let mut buffer: [u8; 1024] = [0; 1024];
let mut hosts = HashMap::new();
loop {
match receiver.recv_timeout(time::Duration::from_millis(10)) {
Ok(msg) => match msg {
ServiceControl::Register { hostname, address } => {
trace!("Registering {} for: {}", hostname, address);
match address.parse().and_then(|ip| {
Ok(match ip {
net::IpAddr::V4(ip) => ip.octets().to_vec(),
net::IpAddr::V6(ip) => ip.octets().to_vec(),
})
}) {
Ok(octets) => {
let mut v = Vec::new();
v.extend(octets);
hosts.insert(hostname, v);
}
Err(err) => {
warn!(
"Could not parse address for {}: {}: {}",
hostname, address, err
);
}
}
}
ServiceControl::Unregister { hostname } => {
trace!("Unregistering {}", hostname);
hosts.remove(&hostname);
}
ServiceControl::Stop => {
trace!("Stopping");
break;
}
},
Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
break;
}
_ => {}
}
match socket.recv_from(&mut buffer) {
Ok((amt, _)) => {
if amt > 0 {
let buffer = &buffer[0..amt];
match dns_parser::Packet::parse(&buffer) {
Ok(parsed) => {
let mut answers: Vec<(String, &[u8])> = Vec::new();
parsed
.questions
.iter()
.filter(|question| {
question.qtype == dns_parser::QueryType::A
})
.for_each(|question| {
let qname = question.qname.to_string();
trace!("mDNS question: {} {:?}", qname, question.qtype);
if let Some(octets) = hosts.get(&qname) {
trace!(
"Sending mDNS answer for {}: {:?}",
qname,
octets
);
answers.push((qname, &octets));
}
});
// TODO: If we did not answer every query
// in this question, we should wait for a
// random amount of time so as to not
// collide with someone else responding to
// this query.
if answers.len() > 0 {
if let Ok(buf) = create_answer(parsed.header.id, &answers) {
if let Err(err) = socket.send_to(&buf, &mdns_addr) {
warn!("Sending mDNS answer failed: {}", err);
}
}
}
}
Err(err) => {
warn!("Could not parse mDNS packet: {}", err);
}
}
}
}
Err(err) => {
if err.kind() != io::ErrorKind::WouldBlock
&& err.kind() != io::ErrorKind::TimedOut
{
error!("Socket error: {}", err);
break;
}
}
}
}
})?;
Ok(())
}
fn stop(self) {
if let Some(sender) = self.sender {
if let Err(err) = sender.send(ServiceControl::Stop) {
warn!("Could not stop mDNS Service: {}", err);
}
}
}
fn new() -> MDNSService {
MDNSService { sender: None }
}
}
#[no_mangle]
pub extern "C" fn mdns_service_register_hostname(
serv: *mut MDNSService,
hostname: *const c_char,
address: *const c_char,
) {
unsafe {
let hostname = CStr::from_ptr(hostname).to_string_lossy();
let address = CStr::from_ptr(address).to_string_lossy();
(*serv).register_hostname(&hostname, &address);
}
}
#[no_mangle]
pub extern "C" fn mdns_service_start(ifaddr: *const c_char) -> *mut MDNSService {
let mut r = Box::new(MDNSService::new());
unsafe {
let ifaddr = CStr::from_ptr(ifaddr).to_string_lossy();
if let Ok(addr) = ifaddr.parse() {
if let Err(err) = r.start(addr) {
warn!("Could not start mDNS Service: {}", err);
}
} else {
warn!("Could not parse interface address: {}", ifaddr);
}
}
Box::into_raw(r)
}
#[no_mangle]
pub extern "C" fn mdns_service_stop(serv: *mut MDNSService) {
unsafe {
let boxed = Box::from_raw(serv);
boxed.stop();
}
}
#[no_mangle]
pub extern "C" fn mdns_service_unregister_hostname(
serv: *mut MDNSService,
hostname: *const c_char,
) {
unsafe {
let hostname = CStr::from_ptr(hostname).to_string_lossy();
(*serv).unregister_hostname(&hostname);
}
}
#[no_mangle]
pub extern "C" fn mdns_service_generate_uuid() -> *const c_char {
let uuid = Uuid::new_v4().to_hyphenated().to_string();
match CString::new(uuid) {
Ok(uuid) => {
uuid.into_raw()
}
Err(_) => unreachable!() // UUID should not contain 0 byte
}
}
#[no_mangle]
pub extern "C" fn mdns_service_free_uuid(uuid: *mut c_char) {
unsafe {
CString::from_raw(uuid);
}
}

View File

@ -57,7 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "nsComponentManagerUtils.h"
#include "nsError.h"
#include "nsIEventTarget.h"
#include "nsIUUIDGenerator.h"
#include "nsNetCID.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
@ -97,10 +96,6 @@ extern "C" {
#include "rlogconnector.h"
#include "test_nr_socket.h"
extern "C" {
#include "mdns_service/mdns_service.h"
}
namespace mozilla {
using std::shared_ptr;
@ -280,8 +275,7 @@ NrIceCtx::NrIceCtx(const std::string& name, Policy policy)
policy_(policy),
nat_(nullptr),
proxy_config_(nullptr),
proxy_only_(false),
obfuscate_host_addresses_(false) {}
proxy_only_(false) {}
/* static */
RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name, bool allow_loopback,
@ -433,14 +427,10 @@ void NrIceCtx::trickle_cb(void* arg, nr_ice_ctx* ice_ctx,
}
if (!candidate) {
s->SignalCandidate(s, "", stream->ufrag, "", "");
s->SignalCandidate(s, "", stream->ufrag);
return;
}
std::string actual_addr;
std::string mdns_addr;
ctx->GenerateObfuscatedAddress(candidate, &mdns_addr, &actual_addr);
// Format the candidate.
char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
int r = nr_ice_format_candidate_attribute(candidate, candidate_str,
@ -451,7 +441,7 @@ void NrIceCtx::trickle_cb(void* arg, nr_ice_ctx* ice_ctx,
MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
<< candidate_str);
s->SignalCandidate(s, candidate_str, stream->ufrag, mdns_addr, actual_addr);
s->SignalCandidate(s, candidate_str, stream->ufrag);
}
void NrIceCtx::InitializeGlobals(bool allow_loopback, bool tcp_enabled,
@ -868,12 +858,8 @@ void NrIceCtx::SetCtxFlags(bool default_route_only, bool proxy_only) {
}
}
nsresult NrIceCtx::StartGathering(bool default_route_only, bool proxy_only,
bool obfuscate_host_addresses) {
nsresult NrIceCtx::StartGathering(bool default_route_only, bool proxy_only) {
ASSERT_ON_THREAD(sts_target_);
obfuscate_host_addresses_ = obfuscate_host_addresses;
SetGatheringState(ICE_CTX_GATHER_STARTED);
SetCtxFlags(default_route_only, proxy_only);
@ -1047,35 +1033,6 @@ void NrIceCtx::SetGatheringState(GatheringState state) {
SignalGatheringStateChange(this, state);
}
void NrIceCtx::GenerateObfuscatedAddress(nr_ice_candidate* candidate,
std::string* mdns_address,
std::string* actual_address) {
if (candidate->type == HOST && obfuscate_host_addresses_) {
int r;
char addr[64];
if ((r = nr_transport_addr_get_addrstring(&candidate->addr, addr,
sizeof(addr)))) {
return;
}
*actual_address = addr;
const auto& iter = obfuscated_host_addresses_.find(*actual_address);
if (iter != obfuscated_host_addresses_.end()) {
*mdns_address = iter->second;
} else {
const char* uuid = mdns_service_generate_uuid();
std::ostringstream o;
o << uuid << ".local";
*mdns_address = o.str();
mdns_service_free_uuid(uuid);
obfuscated_host_addresses_[*actual_address] = *mdns_address;
}
candidate->mdns_addr = r_strdup(mdns_address->c_str());
}
}
} // namespace mozilla
// Reimplement nr_ice_compute_codeword to avoid copyright issues

View File

@ -311,8 +311,7 @@ class NrIceCtx {
bool proxy_only() const { return proxy_only_; }
// Start ICE gathering
nsresult StartGathering(bool default_route_only, bool proxy_only,
bool obfuscate_host_addresses);
nsresult StartGathering(bool default_route_only, bool proxy_only);
// Start checking
nsresult StartChecks();
@ -377,10 +376,6 @@ class NrIceCtx {
// Set the state
void SetGatheringState(GatheringState state);
void GenerateObfuscatedAddress(nr_ice_candidate* candidate,
std::string* mdns_address,
std::string* actual_address);
ConnectionState connection_state_;
GatheringState gathering_state_;
const std::string name_;
@ -396,8 +391,6 @@ class NrIceCtx {
RefPtr<TestNat> nat_;
std::shared_ptr<NrSocketProxyConfig> proxy_config_;
bool proxy_only_;
bool obfuscate_host_addresses_;
std::map<std::string, std::string> obfuscated_host_addresses_;
};
} // namespace mozilla

View File

@ -194,8 +194,7 @@ class NrIceMediaStream {
// the candidate belongs to.
const std::string& GetId() const { return id_; }
sigslot::signal5<NrIceMediaStream*, const std::string&, const std::string&,
const std::string&, const std::string&>
sigslot::signal3<NrIceMediaStream*, const std::string&, const std::string&>
SignalCandidate; // A new ICE candidate:
sigslot::signal1<NrIceMediaStream*> SignalReady; // Candidate pair ready.

View File

@ -537,7 +537,7 @@ class IceTestPeer : public sigslot::has_slots<> {
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, ice_ctx_, &NrIceCtx::StartGathering,
default_route_only, false, false),
default_route_only, false),
NS_DISPATCH_SYNC);
ASSERT_TRUE(NS_SUCCEEDED(res));
@ -984,9 +984,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void CandidateInitialized(NrIceMediaStream* stream,
const std::string& raw_candidate,
const std::string& ufrag,
const std::string& mdns_addr,
const std::string& actual_addr) {
const std::string& ufrag) {
std::string candidate(FilterCandidate(raw_candidate));
if (candidate.empty()) {
return;

View File

@ -619,7 +619,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
// Start gathering
test_utils_->sts_target()->Dispatch(
WrapRunnableRet(&res, ice_ctx_, &NrIceCtx::StartGathering, false, false,
WrapRunnableRet(&res, ice_ctx_, &NrIceCtx::StartGathering, false,
false),
NS_DISPATCH_SYNC);
ASSERT_TRUE(NS_SUCCEEDED(res));
@ -634,8 +634,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
// New candidate
void GotCandidate(NrIceMediaStream* stream, const std::string& candidate,
const std::string& ufrag, const std::string& mdns_addr,
const std::string& actual_addr) {
const std::string& ufrag) {
std::cerr << "Got candidate " << candidate << " (ufrag=" << ufrag << ")"
<< std::endl;
}

View File

@ -947,14 +947,8 @@ int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int ma
assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
if (cand->mdns_addr) {
/* mdns_addr is NSID_LENGTH which is 39, - 2 for removing the "{" and "}"
+ 6 for ".local" for a total of 43. */
strncpy(addr, cand->mdns_addr, sizeof(addr) - 1);
} else {
if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
ABORT(r);
}
if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
ABORT(r);
if(r=nr_transport_addr_get_port(&cand->addr,&port))
ABORT(r);
/* https://tools.ietf.org/html/rfc6544#section-4.5 */

View File

@ -167,7 +167,7 @@ class LoopbackTransport : public MediaTransportHandler {
// capture permissions have been granted on the window, which could easily
// change between Init (ie; when the PC is created) and StartIceGathering
// (ie; when we set the local description).
void StartIceGathering(bool aDefaultRouteOnly, bool aObfuscateAddresses,
void StartIceGathering(bool aDefaultRouteOnly,
// TODO: It probably makes sense to look
// this up internally
const nsTArray<NrIceStunAddr>& aStunAddrs) override {}

View File

@ -13,8 +13,6 @@ namespace mozilla {
// This is used both by IPDL code, and by signaling code.
struct CandidateInfo {
std::string mCandidate;
std::string mMDNSAddress;
std::string mActualAddress;
std::string mUfrag;
std::string mDefaultHostRtp;
uint16_t mDefaultPortRtp = 0;

View File

@ -86,7 +86,7 @@ class MediaTransportHandlerSTS : public MediaTransportHandler,
// capture permissions have been granted on the window, which could easily
// change between Init (ie; when the PC is created) and StartIceGathering
// (ie; when we set the local description).
void StartIceGathering(bool aDefaultRouteOnly, bool aObfuscateHostAddresses,
void StartIceGathering(bool aDefaultRouteOnly,
// This will go away once mtransport moves to its
// own process, because we won't need to get this
// via IPC anymore
@ -147,8 +147,7 @@ class MediaTransportHandlerSTS : public MediaTransportHandler,
NrIceCtx::ConnectionState aState);
void OnCandidateFound(NrIceMediaStream* aStream,
const std::string& aCandidate,
const std::string& aUfrag, const std::string& aMDNSAddr,
const std::string& aActualAddr);
const std::string& aUfrag);
void OnStateChange(TransportLayer* aLayer, TransportLayer::State);
void OnRtcpStateChange(TransportLayer* aLayer, TransportLayer::State);
void PacketReceived(TransportLayer* aLayer, MediaPacket& aPacket);
@ -657,8 +656,7 @@ void MediaTransportHandlerSTS::SetTargetForDefaultLocalAddressLookup(
}
void MediaTransportHandlerSTS::StartIceGathering(
bool aDefaultRouteOnly, bool aObfuscateHostAddresses,
const nsTArray<NrIceStunAddr>& aStunAddrs) {
bool aDefaultRouteOnly, const nsTArray<NrIceStunAddr>& aStunAddrs) {
mInitPromise->Then(
mStsThread, __func__,
[=, self = RefPtr<MediaTransportHandlerSTS>(this)]() {
@ -678,8 +676,7 @@ void MediaTransportHandlerSTS::StartIceGathering(
// Start gathering, but only if there are streams
if (!mIceCtx->GetStreams().empty()) {
mIceCtx->StartGathering(aDefaultRouteOnly, mProxyOnly,
aObfuscateHostAddresses);
mIceCtx->StartGathering(aDefaultRouteOnly, mProxyOnly);
return;
}
@ -1360,10 +1357,9 @@ void MediaTransportHandlerSTS::OnConnectionStateChange(
}
// The stuff below here will eventually go into the MediaTransportChild class
void MediaTransportHandlerSTS::OnCandidateFound(
NrIceMediaStream* aStream, const std::string& aCandidate,
const std::string& aUfrag, const std::string& aMDNSAddr,
const std::string& aActualAddr) {
void MediaTransportHandlerSTS::OnCandidateFound(NrIceMediaStream* aStream,
const std::string& aCandidate,
const std::string& aUfrag) {
CandidateInfo info;
info.mCandidate = aCandidate;
MOZ_ASSERT(!aUfrag.empty());
@ -1372,13 +1368,8 @@ void MediaTransportHandlerSTS::OnCandidateFound(
NrIceCandidate defaultRtcpCandidate;
nsresult rv = aStream->GetDefaultCandidate(1, &defaultRtpCandidate);
if (NS_SUCCEEDED(rv)) {
if (!defaultRtpCandidate.mdns_addr.empty()) {
info.mDefaultHostRtp = "0.0.0.0";
info.mDefaultPortRtp = 9;
} else {
info.mDefaultHostRtp = defaultRtpCandidate.cand_addr.host;
info.mDefaultPortRtp = defaultRtpCandidate.cand_addr.port;
}
info.mDefaultHostRtp = defaultRtpCandidate.cand_addr.host;
info.mDefaultPortRtp = defaultRtpCandidate.cand_addr.port;
} else {
CSFLogError(LOGTAG,
"%s: GetDefaultCandidates failed for transport id %s, "
@ -1389,17 +1380,10 @@ void MediaTransportHandlerSTS::OnCandidateFound(
// Optional; component won't exist if doing rtcp-mux
if (NS_SUCCEEDED(aStream->GetDefaultCandidate(2, &defaultRtcpCandidate))) {
if (!defaultRtcpCandidate.mdns_addr.empty()) {
info.mDefaultHostRtcp = defaultRtcpCandidate.mdns_addr;
} else {
info.mDefaultHostRtcp = defaultRtcpCandidate.cand_addr.host;
}
info.mDefaultHostRtcp = defaultRtcpCandidate.cand_addr.host;
info.mDefaultPortRtcp = defaultRtcpCandidate.cand_addr.port;
}
info.mMDNSAddress = aMDNSAddr;
info.mActualAddress = aActualAddr;
OnCandidate(aStream->GetId(), info);
}
@ -1435,8 +1419,9 @@ NS_IMPL_ISUPPORTS(MediaTransportHandlerSTS::DNSListener, nsIDNSListener);
nsresult MediaTransportHandlerSTS::DNSListener::OnLookupComplete(
nsICancelable* aRequest, nsIDNSRecord* aRecord, nsresult aStatus) {
MOZ_ASSERT(mTransportHandler.mStsThread->IsOnCurrentThread());
if (mCancel) {
MOZ_ASSERT(mTransportHandler.mStsThread->IsOnCurrentThread());
if (NS_SUCCEEDED(aStatus)) {
nsTArray<net::NetAddr> addresses;
aRecord->GetAddresses(addresses);

View File

@ -86,7 +86,6 @@ class MediaTransportHandler {
// change between Init (ie; when the PC is created) and StartIceGathering
// (ie; when we set the local description).
virtual void StartIceGathering(bool aDefaultRouteOnly,
bool aObfuscateHostAddresses,
// TODO: It probably makes sense to look
// this up internally
const nsTArray<NrIceStunAddr>& aStunAddrs) = 0;

View File

@ -209,15 +209,14 @@ void MediaTransportHandlerIPC::SetTargetForDefaultLocalAddressLookup(
// change between Init (ie; when the PC is created) and StartIceGathering
// (ie; when we set the local description).
void MediaTransportHandlerIPC::StartIceGathering(
bool aDefaultRouteOnly, bool aObfuscateHostAddresses,
bool aDefaultRouteOnly,
// TODO(bug 1522205): It probably makes sense to look this up internally
const nsTArray<NrIceStunAddr>& aStunAddrs) {
mInitPromise->Then(
mCallbackThread, __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendStartIceGathering(aDefaultRouteOnly,
aObfuscateHostAddresses, aStunAddrs);
mChild->SendStartIceGathering(aDefaultRouteOnly, aStunAddrs);
}
},
[](const nsCString& aError) {});

View File

@ -43,7 +43,7 @@ class MediaTransportHandlerIPC : public MediaTransportHandler {
// capture permissions have been granted on the window, which could easily
// change between Init (ie; when the PC is created) and StartIceGathering
// (ie; when we set the local description).
void StartIceGathering(bool aDefaultRouteOnly, bool aObfuscateHostAddresses,
void StartIceGathering(bool aDefaultRouteOnly,
// TODO: It probably makes sense to look
// this up internally
const nsTArray<NrIceStunAddr>& aStunAddrs) override;

View File

@ -158,10 +158,8 @@ MediaTransportParent::RecvSetTargetForDefaultLocalAddressLookup(
}
mozilla::ipc::IPCResult MediaTransportParent::RecvStartIceGathering(
const bool& defaultRouteOnly, const bool& obfuscateHostAddresses,
const net::NrIceStunAddrArray& stunAddrs) {
mImpl->mHandler->StartIceGathering(defaultRouteOnly, obfuscateHostAddresses,
stunAddrs);
const bool& defaultRouteOnly, const net::NrIceStunAddrArray& stunAddrs) {
mImpl->mHandler->StartIceGathering(defaultRouteOnly, stunAddrs);
return ipc::IPCResult::Ok();
}

View File

@ -52,6 +52,7 @@ void PeerConnectionMedia::StunAddrsHandler::OnStunAddrsAvailable(
if (pcm_) {
pcm_->mStunAddrs = addrs;
pcm_->mLocalAddrsCompleted = true;
pcm_->mStunAddrsRequest = nullptr;
pcm_->FlushIceCtxOperationQueueIfReady();
// If parent process returns 0 STUN addresses, change ICE connection
// state to failed.
@ -72,29 +73,33 @@ PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl* parent)
mSTSThread(mParent->GetSTSThread()),
mProxyResolveCompleted(false),
mProxyConfig(nullptr),
mStunAddrsRequest(nullptr),
mLocalAddrsCompleted(false),
mTargetForDefaultLocalAddressLookupIsSet(false),
mDestroyed(false) {
if (XRE_IsContentProcess()) {
nsCOMPtr<nsIEventTarget> target =
mParent->GetWindow()
? mParent->GetWindow()->EventTargetFor(TaskCategory::Other)
: nullptr;
mStunAddrsRequest =
new net::StunAddrsRequestChild(new StunAddrsHandler(this), target);
}
}
mDestroyed(false) {}
PeerConnectionMedia::~PeerConnectionMedia() {
MOZ_RELEASE_ASSERT(!mMainThread);
}
void PeerConnectionMedia::InitLocalAddrs() {
if (mStunAddrsRequest) {
if (XRE_IsContentProcess()) {
CSFLogDebug(LOGTAG, "%s: Get stun addresses via IPC",
mParentHandle.c_str());
nsCOMPtr<nsIEventTarget> target =
mParent->GetWindow()
? mParent->GetWindow()->EventTargetFor(TaskCategory::Other)
: nullptr;
// We're in the content process, so send a request over IPC for the
// stun address discovery.
mStunAddrsRequest =
new net::StunAddrsRequestChild(new StunAddrsHandler(this), target);
mStunAddrsRequest->SendGetStunAddrs();
} else {
// No content process, so don't need to hold up the ice event queue
// until completion of stun address discovery. We can let the
// discovery of stun addresses happen in the same process.
mLocalAddrsCompleted = true;
}
}
@ -299,18 +304,6 @@ bool PeerConnectionMedia::GetPrefDefaultAddressOnly() const {
return default_address_only;
}
bool PeerConnectionMedia::GetPrefObfuscateHostAddresses() const {
ASSERT_ON_THREAD(mMainThread); // will crash on STS thread
uint64_t winId = mParent->GetWindow()->WindowID();
bool obfuscate_host_addresses = Preferences::GetBool(
"media.peerconnection.ice.obfuscate_host_addresses", false);
obfuscate_host_addresses &=
!MediaManager::Get()->IsActivelyCapturingOrHasAPermission(winId);
return obfuscate_host_addresses;
}
void PeerConnectionMedia::ConnectSignals() {
mTransportHandler->SignalGatheringStateChange.connect(
this, &PeerConnectionMedia::IceGatheringStateChange_s);
@ -362,8 +355,7 @@ void PeerConnectionMedia::GatherIfReady() {
mQueuedIceCtxOperations.clear();
nsCOMPtr<nsIRunnable> runnable(WrapRunnable(
RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::EnsureIceGathering, GetPrefDefaultAddressOnly(),
GetPrefObfuscateHostAddresses()));
&PeerConnectionMedia::EnsureIceGathering, GetPrefDefaultAddressOnly()));
PerformOrEnqueueIceCtxOperation(runnable);
}
@ -413,8 +405,7 @@ nsresult PeerConnectionMedia::SetTargetForDefaultLocalAddressLookup() {
return NS_OK;
}
void PeerConnectionMedia::EnsureIceGathering(bool aDefaultRouteOnly,
bool aObfuscateHostAddresses) {
void PeerConnectionMedia::EnsureIceGathering(bool aDefaultRouteOnly) {
if (mProxyConfig) {
// Note that this could check if PrivacyRequested() is set on the PC and
// remove "webrtc" from the ALPN list. But that would only work if the PC
@ -444,8 +435,7 @@ void PeerConnectionMedia::EnsureIceGathering(bool aDefaultRouteOnly,
return;
}
mTransportHandler->StartIceGathering(aDefaultRouteOnly,
aObfuscateHostAddresses, mStunAddrs);
mTransportHandler->StartIceGathering(aDefaultRouteOnly, mStunAddrs);
}
void PeerConnectionMedia::SelfDestruct() {
@ -456,11 +446,6 @@ void PeerConnectionMedia::SelfDestruct() {
mDestroyed = true;
if (mStunAddrsRequest) {
for (auto& hostname : mRegisteredMDNSHostnames) {
mStunAddrsRequest->SendUnregisterMDNSHostname(
nsCString(hostname.c_str()));
}
mRegisteredMDNSHostnames.clear();
mStunAddrsRequest->Cancel();
mStunAddrsRequest = nullptr;
}
@ -672,21 +657,6 @@ void PeerConnectionMedia::OnCandidateFound_m(
if (mParent) {
mParent->OnCandidateFound(aTransportId, aCandidateInfo);
}
if (mStunAddrsRequest && !aCandidateInfo.mMDNSAddress.empty()) {
MOZ_ASSERT(!aCandidateInfo.mActualAddress.empty());
auto itor = mRegisteredMDNSHostnames.find(aCandidateInfo.mMDNSAddress);
// We'll see the address twice if we're generating both UDP and TCP
// candidates.
if (itor == mRegisteredMDNSHostnames.end()) {
mRegisteredMDNSHostnames.insert(aCandidateInfo.mMDNSAddress);
mStunAddrsRequest->SendRegisterMDNSHostname(
nsCString(aCandidateInfo.mMDNSAddress.c_str()),
nsCString(aCandidateInfo.mActualAddress.c_str()));
}
}
}
void PeerConnectionMedia::AlpnNegotiated_s(const std::string& aAlpn) {

View File

@ -167,10 +167,9 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
void FlushIceCtxOperationQueueIfReady();
void PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable);
nsresult SetTargetForDefaultLocalAddressLookup();
void EnsureIceGathering(bool aDefaultRouteOnly, bool aObfuscateHostAddresses);
void EnsureIceGathering(bool aDefaultRouteOnly);
bool GetPrefDefaultAddressOnly() const;
bool GetPrefObfuscateHostAddresses() const;
void ConnectSignals();
@ -231,9 +230,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Set to true when the object is going to be released.
bool mDestroyed;
// Used to store the mDNS hostnames that we have registered
std::set<std::string> mRegisteredMDNSHostnames;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PeerConnectionMedia)
};

View File

@ -551,7 +551,6 @@ pref("media.videocontrols.picture-in-picture.video-toggle.always-show", false);
pref("media.peerconnection.ice.trickle_grace_period", 5000);
pref("media.peerconnection.ice.no_host", false);
pref("media.peerconnection.ice.default_address_only", false);
pref("media.peerconnection.ice.obfuscate_host_addresses", false);
pref("media.peerconnection.ice.proxy_only_if_behind_proxy", false);
pref("media.peerconnection.ice.proxy_only", false);
pref("media.peerconnection.turn.disable", false);

View File

@ -254,14 +254,16 @@ def check_networking(binary):
retcode = 0
networking_functions = set([
# socketpair is not concerning; it is restricted to AF_UNIX
"connect", "accept", "listen", "getsockname", "getsockopt",
"recv", "send",
"socket", "connect", "accept", "bind", "listen",
"getsockname", "getsockopt", "setsockopt",
"recv", "recvfrom",
"send", "sendto",
# We would be concerned by recvmsg and sendmsg; but we believe
# they are okay as documented in 1376621#c23
"gethostbyname", "gethostbyaddr", "gethostent", "sethostent", "endhostent",
"gethostent_r", "gethostbyname2", "gethostbyaddr_r", "gethostbyname_r",
"gethostbyname2_r",
"getservent", "getservbyname", "getservbyport", "setservent",
"getaddrinfo", "getservent", "getservbyname", "getservbyport", "setservent",
"getprotoent", "getprotobyname", "getprotobynumber", "setprotoent",
"endprotoent"])
bad_occurences_names = set()

View File

@ -1 +0,0 @@
{"files":{"Cargo.toml":"7b47cb4d67f549cce93b578b0911177365055bbbc15790644251cac1856a11f7","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"71fb06f353ef01dbb828a61a74eadbfc57ab4e1b20eaae1db68229f1647c4183","README.md":"85171334a4b9e672811377819e7f178abdd1870f09d1a1250fe25a7ffaf4b5bf","bulk.yaml":"17c2548388e0cd3a63473021a2f1e4ddedee082d79d9167cb31ad06a1890d3fc","examples/sync_tcp_client.rs":"8ba349565ae9872fc3e246469eab0f7041355d38100355d07a2c1ff2cd048476","examples/sync_udp_client.rs":"ee32137e43d6ab4da6c6f1b36d956042fb74d2704ec319acd058ca74fdc489c1","src/builder.rs":"1dc20c218e5e3b8d0d0f7cdc7ab585882d9960493881be5f17ad2ea5ce8c9dd5","src/enums.rs":"0e0afe0987805ac7361bb6fcaee8a235f375312fa372a6fc8d9b36a85710a9c9","src/error.rs":"6abc85f52724ef8aa12e1ff40a747a02b018b99ae259880a9ff222959f567200","src/header.rs":"f96466c2c0c5647fab0718e9e8289aa9933e988015e454c38ecb7d3c0b6b6813","src/lib.rs":"98994eb0dfea6864d9cf26e1c6ff32f31249e9eaec4583387524dc919e4dde49","src/name.rs":"3d80f16e473e32780e60d814ea3af54094e8c813af576743b108deaf960da27e","src/parser.rs":"02af73135af936115a0ac99da7d102d5ef3c58890abe98d0cfefcd3814b98463","src/rdata/a.rs":"a66498dc4f02af5c95b53f09e2860fed69881410eb02a30bceee0b976e8f8c41","src/rdata/aaaa.rs":"0163de1dc6a691f2ede528cb865f1197511800742879bda189e65aadd682e6c4","src/rdata/all.rs":"005b8edc4aae6f140332f75420c900bae91be66dfb2fdcdd177d51280bbc3750","src/rdata/axfr.rs":"19e18099a16baf33e34ea23905ec5913834aa367a034343551fe935a367f20db","src/rdata/cname.rs":"f31f3c490b6fcd9d5300d4c3903c398cfdd7ff89154685fc3fb182b3fa553ecf","src/rdata/hinfo.rs":"3edd6e2685a048b7d35872582490cdffa90ca7aa688ecffe1d91c46b9ccede1c","src/rdata/maila.rs":"f3f5a40cebd458ed83da7d910601cab761883eee14e991c677d325e6f2fcd968","src/rdata/mailb.rs":"6e09a86dab9a516b4022eefb6a06dcb7d9b06e15d3a80e8027db285e43e5f870","src/rdata/mb.rs":"b867aa5e0f1ec0970d8d6d6406773a8b7af5291dbcf1d8d78be9d017d8cc5a81","src/rdata/mf.rs":"2494cf316f1c2bf803237ce01e7bbbdf05a736fcac2536a06a34ebaf51c815ae","src/rdata/mg.rs":"14a1c9813bc7a33811efa4855c0ac29288cbc1ec535f7c67609333a2a8a5612b","src/rdata/minfo.rs":"72bf7b87ca494865327866ddf9733fb9b137cf2cd4222338237f107b4ff5062d","src/rdata/mod.rs":"0a6f377059eee38371893d17c31d97fb214f209c89c43f5f9302e3560150a220","src/rdata/mr.rs":"0140e5a4c1b6af5e55a61027c21e1760cd2b5a8f1929604d3884225b9433054a","src/rdata/mx.rs":"a38113e7b6efbc65831582fbfacbb6ed1937e167f1b8a19a36a27b0b600ec085","src/rdata/ns.rs":"2acf2d552f3e4f94af50b1c46a6cefc99515a930b099e2d93e9a595f4e1746b5","src/rdata/nsec.rs":"0a712e38c35c60815a2b1394e4bb4f9e229311e80bc9e59b0e854354f928d5a5","src/rdata/null.rs":"0ee8104671d5238da7885b90248ffc952f1558eaa43dfe15b60292166a992a38","src/rdata/opt.rs":"24eb3346b88b3aec18985bd2c1db6498160a59ed7fabfc8b45ce174f10638653","src/rdata/ptr.rs":"9ab2459fc87f90edb2bc7d0fbb97ab008cedf3ce62c042d1b25181914a5ee5c6","src/rdata/soa.rs":"0bf7321ff2891af8f9a3d6b58199464a77b1556e705fa1e9b52f23358bb4bf47","src/rdata/srv.rs":"7d755cb64f42d3096a763739e31959ebec439855380869cd801196bb507102aa","src/rdata/txt.rs":"9e00d2b64cfc53fa8ac510a8c624f5d42320cd90f8a50d040cfc666b530fd8ad","src/rdata/wks.rs":"abfb5572d2c270838489a6ff611c76cb0d3dc7470f44a6810fb89894febd8840","src/structs.rs":"4692edebde24c3be4a7aae81f75b8dc69a9c1ed460bf80740a75bc13f5e40b82","vagga.yaml":"3662f1f49317908fd54ab7830d53074b4bdd753ae85bc3a6fcf6fabaa6b42c70"},"package":"c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"}

View File

@ -1,41 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "dns-parser"
version = "0.8.0"
authors = ["Paul Colomiets <paul@colomiets.name>"]
description = " Pure-rust DNS protocol parser library. This does not support network, only\n raw protocol parser.\n"
homepage = "https://github.com/tailhook/dns-parser"
documentation = "https://docs.rs/dns-parser"
readme = "README.md"
keywords = ["dns", "domain", "name", "parser"]
categories = ["parser-implementations"]
license = "MIT/Apache-2.0"
[dependencies.byteorder]
version = "1"
[dependencies.quick-error]
version = "1.0.0"
[dependencies.serde]
version = "1.0"
optional = true
[dependencies.serde_derive]
version = "1.0"
optional = true
[dev-dependencies.matches]
version = "0.1.2"
[features]
with-serde = ["serde", "serde_derive"]

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,19 +0,0 @@
Copyright (c) 2016 The dns-parser Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,31 +0,0 @@
DNS Parser
==========
**Status: beta**
[Documentation](https://docs.rs/dns-parser) |
[Github](https://github.com/tailhook/dns-parser) |
[Crate](https://crates.io/crates/dns-parser)
This is a parser of DNS protocol packets that is independent of any networking
code.
License
=======
Licensed under either of
* Apache License, Version 2.0,
(./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
------------
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

View File

@ -1,8 +0,0 @@
minimum-bulk: v0.4.5
versions:
- file: Cargo.toml
block-start: ^\[package\]
block-end: ^\[.*\]
regex: ^version\s*=\s*"(\S+)"

View File

@ -1,77 +0,0 @@
extern crate dns_parser;
use std::env;
use std::error::Error;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::process;
use dns_parser::{Builder, Packet, RData, ResponseCode};
use dns_parser::rdata::a::Record;
use dns_parser::{QueryType, QueryClass};
fn main() {
let mut code = 0;
for name in env::args().skip(1) {
match resolve(&name) {
Ok(()) => {},
Err(e) => {
eprintln!("Error resolving {:?}: {}", name, e);
code = 1;
}
}
}
process::exit(code);
}
fn resolve(name: &str) -> Result<(), Box<Error>> {
let mut conn = TcpStream::connect("127.0.0.1:53")?;
let mut builder = Builder::new_query(1, true);
builder.add_question(name, false, QueryType::A, QueryClass::IN);
let packet = builder.build().map_err(|_| "truncated packet")?;
let psize = [((packet.len() >> 8) & 0xFF) as u8,
(packet.len() & 0xFF) as u8];
conn.write_all(&psize[..])?;
conn.write_all(&packet)?;
let mut buf = vec![0u8; 4096];
let mut off = 0;
let pkt = loop {
if buf.len() - off < 4096 {
buf.extend(&[0u8; 4096][..]);
}
match conn.read(&mut buf[off..]) {
Ok(num) => {
off += num;
if off < 2 { continue; }
let bytes = ((buf[0] as usize) << 8) | buf[1] as usize;
if off < bytes + 2 {
continue;
}
if num == 0 {
return Err("Partial packet received".into());
}
break Packet::parse(&buf[2..off])?;
}
Err(e) => {
return Err(Box::new(e));
}
}
};
if pkt.header.response_code != ResponseCode::NoError {
return Err(pkt.header.response_code.into());
}
if pkt.answers.len() == 0 {
return Err("No records received".into());
}
for ans in pkt.answers {
match ans.data {
RData::A(Record(ip)) => {
println!("{}", ip);
}
_ => {} // ignore
}
}
Ok(())
}

View File

@ -1,53 +0,0 @@
extern crate dns_parser;
use std::env;
use std::error::Error;
use std::net::UdpSocket;
use std::process;
use dns_parser::{Builder, Packet, RData, ResponseCode};
use dns_parser::rdata::a::Record;
use dns_parser::{QueryType, QueryClass};
fn main() {
let mut code = 0;
for name in env::args().skip(1) {
match resolve(&name) {
Ok(()) => {},
Err(e) => {
eprintln!("Error resolving {:?}: {}", name, e);
code = 1;
}
}
}
process::exit(code);
}
fn resolve(name: &str) -> Result<(), Box<Error>> {
let sock = UdpSocket::bind("127.0.0.1:0")?;
sock.connect("127.0.0.1:53")?;
let mut builder = Builder::new_query(1, true);
builder.add_question(name, false, QueryType::A, QueryClass::IN);
let packet = builder.build().map_err(|_| "truncated packet")?;
sock.send(&packet)?;
let mut buf = vec![0u8; 4096];
sock.recv(&mut buf)?;
let pkt = Packet::parse(&buf)?;
if pkt.header.response_code != ResponseCode::NoError {
return Err(pkt.header.response_code.into());
}
if pkt.answers.len() == 0 {
return Err("No records received".into());
}
for ans in pkt.answers {
match ans.data {
RData::A(Record(ip)) => {
println!("{}", ip);
}
_ => {} // ignore
}
}
Ok(())
}

View File

@ -1,132 +0,0 @@
use byteorder::{ByteOrder, BigEndian, WriteBytesExt};
use {Opcode, ResponseCode, Header, QueryType, QueryClass};
/// Allows to build a DNS packet
///
/// Both query and answer packets may be built with this interface, although,
/// much of functionality is not implemented yet.
#[derive(Debug)]
pub struct Builder {
buf: Vec<u8>,
}
impl Builder {
/// Creates a new query
///
/// Initially all sections are empty. You're expected to fill
/// the questions section with `add_question`
pub fn new_query(id: u16, recursion: bool) -> Builder {
let mut buf = Vec::with_capacity(512);
let head = Header {
id: id,
query: true,
opcode: Opcode::StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: recursion,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: ResponseCode::NoError,
questions: 0,
answers: 0,
nameservers: 0,
additional: 0,
};
buf.extend([0u8; 12].iter());
head.write(&mut buf[..12]);
Builder { buf: buf }
}
/// Adds a question to the packet
///
/// # Panics
///
/// * Answers, nameservers or additional section has already been written
/// * There are already 65535 questions in the buffer.
/// * When name is invalid
pub fn add_question(&mut self, qname: &str, prefer_unicast: bool,
qtype: QueryType, qclass: QueryClass)
-> &mut Builder
{
if &self.buf[6..12] != b"\x00\x00\x00\x00\x00\x00" {
panic!("Too late to add a question");
}
self.write_name(qname);
self.buf.write_u16::<BigEndian>(qtype as u16).unwrap();
let prefer_unicast: u16 = if prefer_unicast { 0x8000 } else { 0x0000 };
self.buf.write_u16::<BigEndian>(qclass as u16 | prefer_unicast).unwrap();
let oldq = BigEndian::read_u16(&self.buf[4..6]);
if oldq == 65535 {
panic!("Too many questions");
}
BigEndian::write_u16(&mut self.buf[4..6], oldq+1);
self
}
fn write_name(&mut self, name: &str) {
for part in name.split('.') {
assert!(part.len() < 63);
let ln = part.len() as u8;
self.buf.push(ln);
self.buf.extend(part.as_bytes());
}
self.buf.push(0);
}
/// Returns the final packet
///
/// When packet is not truncated method returns `Ok(packet)`. If
/// packet is truncated the method returns `Err(packet)`. In both
/// cases the packet is fully valid.
///
/// In the server implementation you may use
/// `x.build().unwrap_or_else(|x| x)`.
///
/// In the client implementation it's probably unwise to send truncated
/// packet, as it doesn't make sense. Even panicking may be more
/// appropriate.
// TODO(tailhook) does the truncation make sense for TCP, and how
// to treat it for EDNS0?
pub fn build(mut self) -> Result<Vec<u8>,Vec<u8>> {
// TODO(tailhook) optimize labels
if self.buf.len() > 512 {
Header::set_truncated(&mut self.buf[..12]);
Err(self.buf)
} else {
Ok(self.buf)
}
}
}
#[cfg(test)]
mod test {
use QueryType as QT;
use QueryClass as QC;
use super::Builder;
#[test]
fn build_query() {
let mut bld = Builder::new_query(1573, true);
bld.add_question("example.com", false, QT::A, QC::IN);
let result = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01";
assert_eq!(&bld.build().unwrap()[..], &result[..]);
}
#[test]
fn build_unicast_query() {
let mut bld = Builder::new_query(1573, true);
bld.add_question("example.com", true, QT::A, QC::IN);
let result = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x80\x01";
assert_eq!(&bld.build().unwrap()[..], &result[..]);
}
#[test]
fn build_srv_query() {
let mut bld = Builder::new_query(23513, true);
bld.add_question("_xmpp-server._tcp.gmail.com", false, QT::SRV, QC::IN);
let result = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
assert_eq!(&bld.build().unwrap()[..], &result[..]);
}
}

View File

@ -1,299 +0,0 @@
use {Error};
use rdata::Record;
use rdata::*;
/// The TYPE value according to RFC 1035
///
/// All "EXPERIMENTAL" markers here are from the RFC
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Type {
/// a host addresss
A = a::Record::TYPE,
/// an authoritative name server
NS = ns::Record::TYPE,
/// a mail forwarder (Obsolete - use MX)
MF = mf::Record::TYPE,
/// the canonical name for an alias
CNAME = cname::Record::TYPE,
/// marks the start of a zone of authority
SOA = soa::Record::TYPE,
/// a mailbox domain name (EXPERIMENTAL)
MB = mb::Record::TYPE,
/// a mail group member (EXPERIMENTAL)
MG = mg::Record::TYPE,
/// a mail rename domain name (EXPERIMENTAL)
MR = mr::Record::TYPE,
/// a null RR (EXPERIMENTAL)
NULL = null::Record::TYPE,
/// a well known service description
WKS = wks::Record::TYPE,
/// a domain name pointer
PTR = ptr::Record::TYPE,
/// host information
HINFO = hinfo::Record::TYPE,
/// mailbox or mail list information
MINFO = minfo::Record::TYPE,
/// mail exchange
MX = mx::Record::TYPE,
/// text strings
TXT = txt::Record::TYPE,
/// IPv6 host address (RFC 2782)
AAAA = aaaa::Record::TYPE,
/// service record (RFC 2782)
SRV = srv::Record::TYPE,
/// EDNS0 options (RFC 6891)
OPT = opt::Record::TYPE,
/// next secure record (RFC 4034, RFC 6762)
NSEC = nsec::Record::TYPE,
}
/// The QTYPE value according to RFC 1035
///
/// All "EXPERIMENTAL" markers here are from the RFC
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))]
pub enum QueryType {
/// a host addresss
A = a::Record::TYPE,
/// an authoritative name server
NS = ns::Record::TYPE,
/// a mail forwarder (Obsolete - use MX)
MF = mf::Record::TYPE,
/// the canonical name for an alias
CNAME = cname::Record::TYPE,
/// marks the start of a zone of authority
SOA = soa::Record::TYPE,
/// a mailbox domain name (EXPERIMENTAL)
MB = mb::Record::TYPE,
/// a mail group member (EXPERIMENTAL)
MG = mg::Record::TYPE,
/// a mail rename domain name (EXPERIMENTAL)
MR = mr::Record::TYPE,
/// a null RR (EXPERIMENTAL)
NULL = null::Record::TYPE,
/// a well known service description
WKS = wks::Record::TYPE,
/// a domain name pointer
PTR = ptr::Record::TYPE,
/// host information
HINFO = hinfo::Record::TYPE,
/// mailbox or mail list information
MINFO = minfo::Record::TYPE,
/// mail exchange
MX = mx::Record::TYPE,
/// text strings
TXT = txt::Record::TYPE,
/// IPv6 host address (RFC 2782)
AAAA = aaaa::Record::TYPE,
/// service record (RFC 2782)
SRV = srv::Record::TYPE,
/// A request for a transfer of an entire zone
AXFR = axfr::Record::TYPE,
/// A request for mailbox-related records (MB, MG or MR)
MAILB = mailb::Record::TYPE,
/// A request for mail agent RRs (Obsolete - see MX)
MAILA = maila::Record::TYPE,
/// A request for all records
All = all::Record::TYPE,
}
/// The CLASS value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Class {
/// the Internet
IN = 1,
/// the CSNET class (Obsolete - used only for examples in some obsolete
/// RFCs)
CS = 2,
/// the CHAOS class
CH = 3,
/// Hesiod [Dyer 87]
HS = 4,
}
/// The QCLASS value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum QueryClass {
/// the Internet
IN = 1,
/// the CSNET class (Obsolete - used only for examples in some obsolete
/// RFCs)
CS = 2,
/// the CHAOS class
CH = 3,
/// Hesiod [Dyer 87]
HS = 4,
/// Any class
Any = 255,
}
/// The OPCODE value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Opcode {
/// Normal query
StandardQuery,
/// Inverse query (query a name by IP)
InverseQuery,
/// Server status request
ServerStatusRequest,
/// Reserved opcode for future use
Reserved(u16),
}
quick_error! {
/// The RCODE value according to RFC 1035
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(missing_docs)] // names are from spec
pub enum ResponseCode {
NoError
FormatError
ServerFailure
NameError
NotImplemented
Refused
Reserved(code: u8)
}
}
impl From<u16> for Opcode {
fn from(code: u16) -> Opcode {
use self::Opcode::*;
match code {
0 => StandardQuery,
1 => InverseQuery,
2 => ServerStatusRequest,
x => Reserved(x),
}
}
}
impl Into<u16> for Opcode {
fn into(self) -> u16 {
use self::Opcode::*;
match self {
StandardQuery => 0,
InverseQuery => 1,
ServerStatusRequest => 2,
Reserved(x) => x,
}
}
}
impl From<u8> for ResponseCode {
fn from(code: u8) -> ResponseCode {
use self::ResponseCode::*;
match code {
0 => NoError,
1 => FormatError,
2 => ServerFailure,
3 => NameError,
4 => NotImplemented,
5 => Refused,
6...15 => Reserved(code),
x => panic!("Invalid response code {}", x),
}
}
}
impl Into<u8> for ResponseCode {
fn into(self) -> u8 {
use self::ResponseCode::*;
match self {
NoError => 0,
FormatError => 1,
ServerFailure => 2,
NameError => 3,
NotImplemented => 4,
Refused => 5,
Reserved(code) => code,
}
}
}
impl QueryType {
/// Parse a query type code
pub fn parse(code: u16) -> Result<QueryType, Error> {
use self::QueryType::*;
match code as isize {
a::Record::TYPE => Ok(A),
ns::Record::TYPE => Ok(NS),
mf::Record::TYPE => Ok(MF),
cname::Record::TYPE => Ok(CNAME),
soa::Record::TYPE => Ok(SOA),
mb::Record::TYPE => Ok(MB),
mg::Record::TYPE => Ok(MG),
mr::Record::TYPE => Ok(MR),
null::Record::TYPE => Ok(NULL),
wks::Record::TYPE => Ok(WKS),
ptr::Record::TYPE => Ok(PTR),
hinfo::Record::TYPE => Ok(HINFO),
minfo::Record::TYPE => Ok(MINFO),
mx::Record::TYPE => Ok(MX),
txt::Record::TYPE => Ok(TXT),
aaaa::Record::TYPE => Ok(AAAA),
srv::Record::TYPE => Ok(SRV),
axfr::Record::TYPE => Ok(AXFR),
mailb::Record::TYPE => Ok(MAILB),
maila::Record::TYPE => Ok(MAILA),
all::Record::TYPE => Ok(All),
x => Err(Error::InvalidQueryType(x as u16)),
}
}
}
impl QueryClass {
/// Parse a query class code
pub fn parse(code: u16) -> Result<QueryClass, Error> {
use self::QueryClass::*;
match code {
1 => Ok(IN),
2 => Ok(CS),
3 => Ok(CH),
4 => Ok(HS),
255 => Ok(Any),
x => Err(Error::InvalidQueryClass(x)),
}
}
}
impl Type {
/// Parse a type code
pub fn parse(code: u16) -> Result<Type, Error> {
use self::Type::*;
match code as isize {
a::Record::TYPE => Ok(A),
ns::Record::TYPE => Ok(NS),
mf::Record::TYPE => Ok(MF),
cname::Record::TYPE => Ok(CNAME),
soa::Record::TYPE => Ok(SOA),
mb::Record::TYPE => Ok(MB),
mg::Record::TYPE => Ok(MG),
mr::Record::TYPE => Ok(MR),
null::Record::TYPE => Ok(NULL),
wks::Record::TYPE => Ok(WKS),
ptr::Record::TYPE => Ok(PTR),
hinfo::Record::TYPE => Ok(HINFO),
minfo::Record::TYPE => Ok(MINFO),
mx::Record::TYPE => Ok(MX),
txt::Record::TYPE => Ok(TXT),
aaaa::Record::TYPE => Ok(AAAA),
srv::Record::TYPE => Ok(SRV),
opt::Record::TYPE => Ok(OPT),
nsec::Record::TYPE => Ok(NSEC),
x => Err(Error::InvalidType(x as u16)),
}
}
}
impl Class {
/// Parse a class code
pub fn parse(code: u16) -> Result<Class, Error> {
use self::Class::*;
match code {
1 => Ok(IN),
2 => Ok(CS),
3 => Ok(CH),
4 => Ok(HS),
x => Err(Error::InvalidClass(x)),
}
}
}

View File

@ -1,71 +0,0 @@
use std::str::Utf8Error;
quick_error! {
/// Error parsing DNS packet
#[derive(Debug)]
pub enum Error {
/// Invalid compression pointer not pointing backwards
/// when parsing label
BadPointer {
description("invalid compression pointer not pointing backwards \
when parsing label")
}
/// Packet is smaller than header size
HeaderTooShort {
description("packet is smaller than header size")
}
/// Packet ihas incomplete data
UnexpectedEOF {
description("packet is has incomplete data")
}
/// Wrong (too short or too long) size of RDATA
WrongRdataLength {
description("wrong (too short or too long) size of RDATA")
}
/// Packet has non-zero reserved bits
ReservedBitsAreNonZero {
description("packet has non-zero reserved bits")
}
/// Label in domain name has unknown label format
UnknownLabelFormat {
description("label in domain name has unknown label format")
}
/// Query type code is invalid
InvalidQueryType(code: u16) {
description("query type code is invalid")
display("query type {} is invalid", code)
}
/// Query class code is invalid
InvalidQueryClass(code: u16) {
description("query class code is invalid")
display("query class {} is invalid", code)
}
/// Type code is invalid
InvalidType(code: u16) {
description("type code is invalid")
display("type {} is invalid", code)
}
/// Class code is invalid
InvalidClass(code: u16) {
description("class code is invalid")
display("class {} is invalid", code)
}
/// Invalid characters encountered while reading label
LabelIsNotAscii {
description("invalid characters encountered while reading label")
}
/// Invalid characters encountered while reading TXT
TxtDataIsNotUTF8(error: Utf8Error) {
description("invalid characters encountered while reading TXT")
display("{:?}", error)
}
/// Parser is in the wrong state
WrongState {
description("parser is in the wrong state")
}
/// Additional OPT record found
AdditionalOPT {
description("additional OPT record found")
}
}
}

View File

@ -1,203 +0,0 @@
use byteorder::{BigEndian, ByteOrder};
use {Error, ResponseCode, Opcode};
mod flag {
pub const QUERY: u16 = 0b1000_0000_0000_0000;
pub const OPCODE_MASK: u16 = 0b0111_1000_0000_0000;
pub const AUTHORITATIVE: u16 = 0b0000_0100_0000_0000;
pub const TRUNCATED: u16 = 0b0000_0010_0000_0000;
pub const RECURSION_DESIRED: u16 = 0b0000_0001_0000_0000;
pub const RECURSION_AVAILABLE: u16 = 0b0000_0000_1000_0000;
pub const AUTHENTICATED_DATA: u16 = 0b0000_0000_0010_0000;
pub const CHECKING_DISABLED: u16 = 0b0000_0000_0001_0000;
pub const RESERVED_MASK: u16 = 0b0000_0000_0100_0000;
pub const RESPONSE_CODE_MASK: u16 = 0b0000_0000_0000_1111;
}
/// Represents parsed header of the packet
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(missing_docs)] // fields are from the spec I think
pub struct Header {
pub id: u16,
pub query: bool,
pub opcode: Opcode,
pub authoritative: bool,
pub truncated: bool,
pub recursion_desired: bool,
pub recursion_available: bool,
pub authenticated_data: bool,
pub checking_disabled: bool,
pub response_code: ResponseCode,
pub questions: u16,
pub answers: u16,
pub nameservers: u16,
pub additional: u16,
}
impl Header {
/// Parse the header into a header structure
pub fn parse(data: &[u8]) -> Result<Header, Error> {
if data.len() < 12 {
return Err(Error::HeaderTooShort);
}
let flags = BigEndian::read_u16(&data[2..4]);
if flags & flag::RESERVED_MASK != 0 {
return Err(Error::ReservedBitsAreNonZero);
}
let header = Header {
id: BigEndian::read_u16(&data[..2]),
query: flags & flag::QUERY == 0,
opcode: ((flags & flag::OPCODE_MASK)
>> flag::OPCODE_MASK.trailing_zeros()).into(),
authoritative: flags & flag::AUTHORITATIVE != 0,
truncated: flags & flag::TRUNCATED != 0,
recursion_desired: flags & flag::RECURSION_DESIRED != 0,
recursion_available: flags & flag::RECURSION_AVAILABLE != 0,
authenticated_data: flags & flag::AUTHENTICATED_DATA != 0,
checking_disabled: flags & flag::CHECKING_DISABLED != 0,
response_code: From::from((flags&flag::RESPONSE_CODE_MASK) as u8),
questions: BigEndian::read_u16(&data[4..6]),
answers: BigEndian::read_u16(&data[6..8]),
nameservers: BigEndian::read_u16(&data[8..10]),
additional: BigEndian::read_u16(&data[10..12]),
};
Ok(header)
}
/// Write a header to a buffer slice
///
/// # Panics
///
/// When buffer size is not exactly 12 bytes
pub fn write(&self, data: &mut [u8]) {
if data.len() != 12 {
panic!("Header size is exactly 12 bytes");
}
let mut flags = 0u16;
flags |= Into::<u16>::into(self.opcode)
<< flag::OPCODE_MASK.trailing_zeros();
flags |= Into::<u8>::into(self.response_code) as u16;
if !self.query { flags |= flag::QUERY; }
if self.authoritative { flags |= flag::AUTHORITATIVE; }
if self.recursion_desired { flags |= flag::RECURSION_DESIRED; }
if self.recursion_available { flags |= flag::RECURSION_AVAILABLE; }
if self.truncated { flags |= flag::TRUNCATED; }
BigEndian::write_u16(&mut data[..2], self.id);
BigEndian::write_u16(&mut data[2..4], flags);
BigEndian::write_u16(&mut data[4..6], self.questions);
BigEndian::write_u16(&mut data[6..8], self.answers);
BigEndian::write_u16(&mut data[8..10], self.nameservers);
BigEndian::write_u16(&mut data[10..12], self.additional);
}
/// Set "truncated flag" in the raw data
// shouldn't this method be non-public?
pub fn set_truncated(data: &mut [u8]) {
let oldflags = BigEndian::read_u16(&data[2..4]);
BigEndian::write_u16(&mut data[2..4], oldflags & flag::TRUNCATED);
}
/// Returns a size of the header (always 12 bytes)
pub fn size() -> usize { 12 }
}
#[cfg(test)]
mod test {
use {Header};
use Opcode::*;
use ResponseCode::NoError;
#[test]
fn parse_example_query() {
let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01";
let header = Header::parse(query).unwrap();
assert_eq!(header, Header {
id: 1573,
query: true,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 0,
nameservers: 0,
additional: 0,
});
}
#[test]
fn parse_example_response() {
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01\
\xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
\x00\x04]\xb8\xd8\"";
let header = Header::parse(response).unwrap();
assert_eq!(header, Header {
id: 1573,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 0,
additional: 0,
});
}
#[test]
fn parse_query_with_ad_set() {
let query = b"\x06%\x01\x20\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01";
let header = Header::parse(query).unwrap();
assert_eq!(header, Header {
id: 1573,
query: true,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: false,
authenticated_data: true,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 0,
nameservers: 0,
additional: 0,
});
}
#[test]
fn parse_query_with_cd_set() {
let query = b"\x06%\x01\x10\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01";
let header = Header::parse(query).unwrap();
assert_eq!(header, Header {
id: 1573,
query: true,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: false,
authenticated_data: false,
checking_disabled: true,
response_code: NoError,
questions: 1,
answers: 0,
nameservers: 0,
additional: 0,
});
}
}

View File

@ -1,39 +0,0 @@
#![recursion_limit="100"]
//! The network-agnostic DNS parser library
//!
//! [Documentation](https://docs.rs/dns-parser) |
//! [Github](https://github.com/tailhook/dns-parser) |
//! [Crate](https://crates.io/crates/dns-parser)
//!
//! Use [`Builder`] to create a new outgoing packet.
//!
//! Use [`Packet::parse`] to parse a packet into a data structure.
//!
//! [`Builder`]: struct.Builder.html
//! [`Packet::parse`]: struct.Packet.html#method.parse
//!
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
extern crate byteorder;
#[cfg(test)] #[macro_use] extern crate matches;
#[macro_use(quick_error)] extern crate quick_error;
#[cfg(feature = "with-serde")] #[macro_use] extern crate serde_derive;
mod enums;
mod structs;
mod name;
mod parser;
mod error;
mod header;
mod builder;
pub mod rdata;
pub use enums::{Type, QueryType, Class, QueryClass, ResponseCode, Opcode};
pub use structs::{Question, ResourceRecord, Packet};
pub use name::{Name};
pub use error::{Error};
pub use header::{Header};
pub use rdata::{RData};
pub use builder::{Builder};

View File

@ -1,183 +0,0 @@
use std::fmt;
use std::fmt::Write;
use std::str::from_utf8;
// Deprecated since rustc 1.23
#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;
use byteorder::{BigEndian, ByteOrder};
use {Error};
/// The DNS name as stored in the original packet
///
/// This contains just a reference to a slice that contains the data.
/// You may turn this into a string using `.to_string()`
#[derive(Clone, Copy)]
pub struct Name<'a>{
labels: &'a [u8],
/// This is the original buffer size. The compressed names in original
/// are calculated in this buffer
original: &'a [u8],
}
impl<'a> Name<'a> {
/// Scan the data to get Name object
///
/// The `data` should be a part of `original` where name should start.
/// The `original` is the data starting a the start of a packet, so
/// that offsets in compressed name starts from the `original`.
pub fn scan(data: &'a[u8], original: &'a[u8]) -> Result<Name<'a>, Error> {
let mut parse_data = data;
let mut return_pos = None;
let mut pos = 0;
if parse_data.len() <= pos {
return Err(Error::UnexpectedEOF);
}
// By setting the largest_pos to be the original len, a side effect
// is that the pos variable can move forwards in the buffer once.
let mut largest_pos = original.len();
let mut byte = parse_data[pos];
while byte != 0 {
if parse_data.len() <= pos {
return Err(Error::UnexpectedEOF);
}
if byte & 0b1100_0000 == 0b1100_0000 {
if parse_data.len() < pos+2 {
return Err(Error::UnexpectedEOF);
}
let off = (BigEndian::read_u16(&parse_data[pos..pos+2])
& !0b1100_0000_0000_0000) as usize;
if off >= original.len() {
return Err(Error::UnexpectedEOF);
}
// Set value for return_pos which is the pos in the original
// data buffer that should be used to return after validating
// the offsetted labels.
if let None = return_pos {
return_pos = Some(pos);
}
// Check then set largest_pos to ensure we never go backwards
// in the buffer.
if off >= largest_pos {
return Err(Error::BadPointer);
}
largest_pos = off;
pos = 0;
parse_data = &original[off..];
} else if byte & 0b1100_0000 == 0 {
let end = pos + byte as usize + 1;
if parse_data.len() < end {
return Err(Error::UnexpectedEOF);
}
if !parse_data[pos+1..end].is_ascii() {
return Err(Error::LabelIsNotAscii);
}
pos = end;
if parse_data.len() <= pos {
return Err(Error::UnexpectedEOF);
}
} else {
return Err(Error::UnknownLabelFormat);
}
byte = parse_data[pos];
}
if let Some(return_pos) = return_pos {
return Ok(Name {labels: &data[..return_pos+2], original: original});
} else {
return Ok(Name {labels: &data[..pos+1], original: original });
}
}
/// Number of bytes serialized name occupies
pub fn byte_len(&self) -> usize {
self.labels.len()
}
}
impl<'a> fmt::Display for Name<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let data = self.labels;
let original = self.original;
let mut pos = 0;
loop {
let byte = data[pos];
if byte == 0 {
return Ok(());
} else if byte & 0b1100_0000 == 0b1100_0000 {
let off = (BigEndian::read_u16(&data[pos..pos+2])
& !0b1100_0000_0000_0000) as usize;
if pos != 0 {
try!(fmt.write_char('.'));
}
return fmt::Display::fmt(
&Name::scan(&original[off..], original).unwrap(), fmt)
} else if byte & 0b1100_0000 == 0 {
if pos != 0 {
try!(fmt.write_char('.'));
}
let end = pos + byte as usize + 1;
try!(fmt.write_str(from_utf8(&data[pos+1..end]).unwrap()));
pos = end;
continue;
} else {
unreachable!();
}
}
}
}
impl<'a> fmt::Debug for Name<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_tuple("Name")
.field(&format!("{}", self))
.finish()
}
}
#[cfg(test)]
mod test {
use Error;
use Name;
#[test]
fn parse_badpointer_same_offset() {
// A buffer where an offset points to itself,
// which is a bad compression pointer.
let same_offset = vec![192, 2, 192, 2];
let is_match = matches!(Name::scan(&same_offset, &same_offset),
Err(Error::BadPointer));
assert!(is_match);
}
#[test]
fn parse_badpointer_forward_offset() {
// A buffer where the offsets points back to each other which causes
// infinite recursion if never checked, a bad compression pointer.
let forwards_offset = vec![192, 2, 192, 4, 192, 2];
let is_match = matches!(Name::scan(&forwards_offset, &forwards_offset),
Err(Error::BadPointer));
assert!(is_match);
}
#[test]
fn nested_names() {
// A buffer where an offset points to itself, a bad compression pointer.
let buf = b"\x02xx\x00\x02yy\xc0\x00\x02zz\xc0\x04";
assert_eq!(Name::scan(&buf[..], buf).unwrap().to_string(),
"xx");
assert_eq!(Name::scan(&buf[..], buf).unwrap().labels,
b"\x02xx\x00");
assert_eq!(Name::scan(&buf[4..], buf).unwrap().to_string(),
"yy.xx");
assert_eq!(Name::scan(&buf[4..], buf).unwrap().labels,
b"\x02yy\xc0\x00");
assert_eq!(Name::scan(&buf[9..], buf).unwrap().to_string(),
"zz.yy.xx");
assert_eq!(Name::scan(&buf[9..], buf).unwrap().labels,
b"\x02zz\xc0\x04");
}
}

View File

@ -1,455 +0,0 @@
use std::i32;
use byteorder::{BigEndian, ByteOrder};
use {Header, Packet, Error, Question, Name, QueryType, QueryClass};
use {Type, Class, ResourceRecord, RData};
use rdata::opt::Record as Opt;
const OPT_RR_START: [u8; 3] = [0, 0, 41];
impl<'a> Packet<'a> {
/// Parse a full DNS Packet and return a structure that has all the
/// data borrowed from the passed buffer.
pub fn parse(data: &[u8]) -> Result<Packet, Error> {
let header = try!(Header::parse(data));
let mut offset = Header::size();
let mut questions = Vec::with_capacity(header.questions as usize);
for _ in 0..header.questions {
let name = try!(Name::scan(&data[offset..], data));
offset += name.byte_len();
if offset + 4 > data.len() {
return Err(Error::UnexpectedEOF);
}
let qtype = try!(QueryType::parse(
BigEndian::read_u16(&data[offset..offset+2])));
offset += 2;
let (prefer_unicast, qclass) = try!(parse_qclass_code(
BigEndian::read_u16(&data[offset..offset+2])));
offset += 2;
questions.push(Question {
qname: name,
qtype: qtype,
prefer_unicast: prefer_unicast,
qclass: qclass,
});
}
let mut answers = Vec::with_capacity(header.answers as usize);
for _ in 0..header.answers {
answers.push(try!(parse_record(data, &mut offset)));
}
let mut nameservers = Vec::with_capacity(header.nameservers as usize);
for _ in 0..header.nameservers {
nameservers.push(try!(parse_record(data, &mut offset)));
}
let mut additional = Vec::with_capacity(header.additional as usize);
let mut opt = None;
for _ in 0..header.additional {
if offset + 3 <= data.len() && data[offset..offset+3] == OPT_RR_START {
if opt.is_none() {
opt = Some(try!(parse_opt_record(data, &mut offset)));
} else {
return Err(Error::AdditionalOPT);
}
} else {
additional.push(try!(parse_record(data, &mut offset)));
}
}
Ok(Packet {
header: header,
questions: questions,
answers: answers,
nameservers: nameservers,
additional: additional,
opt: opt,
})
}
}
fn parse_qclass_code(value: u16) -> Result<(bool, QueryClass), Error> {
let prefer_unicast = value & 0x8000 == 0x8000;
let qclass_code = value & 0x7FFF;
let qclass = try!(QueryClass::parse(qclass_code));
Ok((prefer_unicast, qclass))
}
fn parse_class_code(value: u16) -> Result<(bool, Class), Error> {
let is_unique = value & 0x8000 == 0x8000;
let class_code = value & 0x7FFF;
let cls = try!(Class::parse(class_code));
Ok((is_unique, cls))
}
// Generic function to parse answer, nameservers, and additional records.
fn parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<ResourceRecord<'a>, Error> {
let name = try!(Name::scan(&data[*offset..], data));
*offset += name.byte_len();
if *offset + 10 > data.len() {
return Err(Error::UnexpectedEOF);
}
let typ = try!(Type::parse(
BigEndian::read_u16(&data[*offset..*offset+2])));
*offset += 2;
let class_code = BigEndian::read_u16(&data[*offset..*offset+2]);
let (multicast_unique, cls) = try!(parse_class_code(class_code));
*offset += 2;
let mut ttl = BigEndian::read_u32(&data[*offset..*offset+4]);
if ttl > i32::MAX as u32 {
ttl = 0;
}
*offset += 4;
let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
*offset += 2;
if *offset + rdlen > data.len() {
return Err(Error::UnexpectedEOF);
}
let data = try!(RData::parse(typ,
&data[*offset..*offset+rdlen], data));
*offset += rdlen;
Ok(ResourceRecord {
name: name,
multicast_unique: multicast_unique,
cls: cls,
ttl: ttl,
data: data,
})
}
// Function to parse an RFC 6891 OPT Pseudo RR
fn parse_opt_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<Opt<'a>, Error> {
if *offset + 11 > data.len() {
return Err(Error::UnexpectedEOF);
}
*offset += 1;
let typ = try!(Type::parse(
BigEndian::read_u16(&data[*offset..*offset+2])));
if typ != Type::OPT {
return Err(Error::InvalidType(typ as u16));
}
*offset += 2;
let udp = BigEndian::read_u16(&data[*offset..*offset+2]);
*offset += 2;
let extrcode = data[*offset];
*offset += 1;
let version = data[*offset];
*offset += 1;
let flags = BigEndian::read_u16(&data[*offset..*offset+2]);
*offset += 2;
let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
*offset += 2;
if *offset + rdlen > data.len() {
return Err(Error::UnexpectedEOF);
}
let data = try!(RData::parse(typ,
&data[*offset..*offset+rdlen], data));
*offset += rdlen;
Ok(Opt {
udp: udp,
extrcode: extrcode,
version: version,
flags: flags,
data: data,
})
}
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
#[test]
fn parse_example_query() {
let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01";
let packet = Packet::parse(query).unwrap();
assert_eq!(packet.header, Header {
id: 1573,
query: true,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 0,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
assert_eq!(packet.answers.len(), 0);
}
#[test]
fn parse_example_response() {
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01\
\xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
\x00\x04]\xb8\xd8\"";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 1573,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
assert_eq!(packet.answers.len(), 1);
assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
assert_eq!(packet.answers[0].multicast_unique, false);
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 1272);
match packet.answers[0].data {
RData::A(addr) => {
assert_eq!(addr.0, Ipv4Addr::new(93, 184, 216, 34));
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
#[test]
fn parse_response_with_multicast_unique() {
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x00\x01\
\xc0\x0c\x00\x01\x80\x01\x00\x00\x04\xf8\
\x00\x04]\xb8\xd8\"";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.answers.len(), 1);
assert_eq!(packet.answers[0].multicast_unique, true);
assert_eq!(packet.answers[0].cls, C::IN);
}
#[test]
fn parse_additional_record_response() {
let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x01\
\x03www\x05skype\x03com\x00\x00\x01\x00\x01\
\xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
\x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
\x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
\x72\x03\x6e\x65\x74\x00\
\xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
\x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
\xc0\x42\
\x01\x61\xc0\x55\x00\x01\x00\x01\x00\x00\xa3\x1c\
\x00\x04\xc0\x05\x06\x1e";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 19184,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 1,
additional: 1,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
assert_eq!(packet.answers.len(), 1);
assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 3600);
match packet.answers[0].data {
RData::CNAME(cname) => {
assert_eq!(&cname.0.to_string()[..], "livecms.trafficmanager.net");
}
ref x => panic!("Wrong rdata {:?}", x),
}
assert_eq!(packet.nameservers.len(), 1);
assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
assert_eq!(packet.nameservers[0].cls, C::IN);
assert_eq!(packet.nameservers[0].ttl, 120275);
match packet.nameservers[0].data {
RData::NS(ns) => {
assert_eq!(&ns.0.to_string()[..], "g.gtld-servers.net");
}
ref x => panic!("Wrong rdata {:?}", x),
}
assert_eq!(packet.additional.len(), 1);
assert_eq!(&packet.additional[0].name.to_string()[..], "a.gtld-servers.net");
assert_eq!(packet.additional[0].cls, C::IN);
assert_eq!(packet.additional[0].ttl, 41756);
match packet.additional[0].data {
RData::A(addr) => {
assert_eq!(addr.0, Ipv4Addr::new(192, 5, 6, 30));
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
#[test]
fn parse_multiple_answers() {
let response = b"\x9d\xe9\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\
\x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\
\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\
\xa4d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
\x00\x04@\xe9\xa4\x8b\xc0\x0c\x00\x01\x00\x01\
\x00\x00\x00\xef\x00\x04@\xe9\xa4q\xc0\x0c\x00\
\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\xa4f\
\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\
\xe9\xa4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
\x00\x04@\xe9\xa4\x8a";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 40425,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 6,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
assert_eq!(packet.answers.len(), 6);
let ips = vec![
Ipv4Addr::new(64, 233, 164, 100),
Ipv4Addr::new(64, 233, 164, 139),
Ipv4Addr::new(64, 233, 164, 113),
Ipv4Addr::new(64, 233, 164, 102),
Ipv4Addr::new(64, 233, 164, 101),
Ipv4Addr::new(64, 233, 164, 138),
];
for i in 0..6 {
assert_eq!(&packet.answers[i].name.to_string()[..], "google.com");
assert_eq!(packet.answers[i].cls, C::IN);
assert_eq!(packet.answers[i].ttl, 239);
match packet.answers[i].data {
RData::A(addr) => {
assert_eq!(addr.0, ips[i]);
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}
#[test]
fn parse_srv_query() {
let query = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
let packet = Packet::parse(query).unwrap();
assert_eq!(packet.header, Header {
id: 23513,
query: true,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 0,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::SRV);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(packet.questions[0].prefer_unicast, false);
assert_eq!(&packet.questions[0].qname.to_string()[..],
"_xmpp-server._tcp.gmail.com");
assert_eq!(packet.answers.len(), 0);
}
#[test]
fn parse_multicast_prefer_unicast_query() {
let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
\x07example\x03com\x00\x00\x01\x80\x01";
let packet = Packet::parse(query).unwrap();
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(packet.questions[0].prefer_unicast, true);
}
#[test]
fn parse_example_query_edns() {
let query = b"\x95\xce\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\
\x06google\x03com\x00\x00\x01\x00\
\x01\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00";
let packet = Packet::parse(query).unwrap();
assert_eq!(packet.header, Header {
id: 38350,
query: true,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: false,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 0,
nameservers: 0,
additional: 1,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
assert_eq!(packet.answers.len(), 0);
match packet.opt {
Some(opt) => {
assert_eq!(opt.udp, 4096);
assert_eq!(opt.extrcode, 0);
assert_eq!(opt.version, 0);
assert_eq!(opt.flags, 0);
},
None => panic!("Missing OPT RR")
}
}
}

View File

@ -1,21 +0,0 @@
use std::net::Ipv4Addr;
use Error;
use byteorder::{BigEndian, ByteOrder};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record(pub Ipv4Addr);
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 1;
fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
if rdata.len() != 4 {
return Err(Error::WrongRdataLength);
}
let address = Ipv4Addr::from(BigEndian::read_u32(rdata));
let record = Record(address);
Ok(super::RData::A(record))
}
}

View File

@ -1,85 +0,0 @@
use std::net::Ipv6Addr;
use Error;
use byteorder::{BigEndian, ByteOrder};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record(pub Ipv6Addr);
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 28;
fn parse(rdata: &'a [u8], _record: &'a [u8]) -> super::RDataResult<'a> {
if rdata.len() != 16 {
return Err(Error::WrongRdataLength);
}
let address = Ipv6Addr::new(
BigEndian::read_u16(&rdata[0..2]),
BigEndian::read_u16(&rdata[2..4]),
BigEndian::read_u16(&rdata[4..6]),
BigEndian::read_u16(&rdata[6..8]),
BigEndian::read_u16(&rdata[8..10]),
BigEndian::read_u16(&rdata[10..12]),
BigEndian::read_u16(&rdata[12..14]),
BigEndian::read_u16(&rdata[14..16]),
);
let record = Record(address);
Ok(super::RData::AAAA(record))
}
}
#[cfg(test)]
mod test {
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
use super::*;
#[test]
fn parse_response() {
let response = b"\xa9\xd9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06\
google\x03com\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\
\x00\x8b\x00\x10*\x00\x14P@\t\x08\x12\x00\x00\x00\x00\x00\x00 \x0e";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 43481,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::AAAA);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
assert_eq!(packet.answers.len(), 1);
assert_eq!(&packet.answers[0].name.to_string()[..], "google.com");
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 139);
match packet.answers[0].data {
RData::AAAA(addr) => {
assert_eq!(addr.0, Ipv6Addr::new(
0x2A00, 0x1450, 0x4009, 0x812, 0, 0, 0, 0x200e)
);
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 255;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 252;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,102 +0,0 @@
use Name;
#[derive(Debug, Clone, Copy)]
pub struct Record<'a>(pub Name<'a>);
impl<'a> ToString for Record<'a> {
#[inline]
fn to_string(&self) -> String {
self.0.to_string()
}
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 5;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
let name = Name::scan(rdata, original)?;
let record = Record(name);
Ok(super::RData::CNAME(record))
}
}
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
#[test]
fn parse_response() {
let response = b"\xfc\x9d\x81\x80\x00\x01\x00\x06\x00\x02\x00\x02\x03\
cdn\x07sstatic\x03net\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\
\x00\x00\x00f\x00\x02\xc0\x10\xc0\x10\x00\x01\x00\x01\x00\x00\x00\
f\x00\x04h\x10g\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\
\x10k\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10h\xcc\
\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10j\xcc\xc0\x10\
\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10i\xcc\xc0\x10\x00\x02\
\x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns02\xc0\x10\xc0\x10\x00\x02\
\x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns01\xc0\x10\xc0\xa2\x00\x01\
\x00\x01\x00\x00\x99L\x00\x04\xad\xf5:5\xc0\x8b\x00\x01\x00\x01\x00\
\x00\x99L\x00\x04\xad\xf5;\x04";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 64669,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 6,
nameservers: 2,
additional: 2,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "cdn.sstatic.net");
assert_eq!(packet.answers.len(), 6);
assert_eq!(&packet.answers[0].name.to_string()[..], "cdn.sstatic.net");
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 102);
match packet.answers[0].data {
RData::CNAME(cname) => {
assert_eq!(&cname.0.to_string(), "sstatic.net");
}
ref x => panic!("Wrong rdata {:?}", x),
}
let ips = vec![
Ipv4Addr::new(104, 16, 103, 204),
Ipv4Addr::new(104, 16, 107, 204),
Ipv4Addr::new(104, 16, 104, 204),
Ipv4Addr::new(104, 16, 106, 204),
Ipv4Addr::new(104, 16, 105, 204),
];
for i in 1..6 {
assert_eq!(&packet.answers[i].name.to_string()[..], "sstatic.net");
assert_eq!(packet.answers[i].cls, C::IN);
assert_eq!(packet.answers[i].ttl, 102);
match packet.answers[i].data {
RData::A(addr) => {
assert_eq!(addr.0, ips[i-1]);
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 13;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 254;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 253;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 7;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 4;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 8;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 14;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,83 +0,0 @@
//! Data types and methods for handling the RData field
#![allow(missing_docs)] // resource records are pretty self-descriptive
pub mod a;
pub mod aaaa;
pub mod all;
pub mod axfr;
pub mod cname;
pub mod hinfo;
pub mod maila;
pub mod mailb;
pub mod mb;
pub mod mf;
pub mod mg;
pub mod minfo;
pub mod mr;
pub mod mx;
pub mod ns;
pub mod nsec;
pub mod null;
pub mod opt;
pub mod ptr;
pub mod soa;
pub mod srv;
pub mod txt;
pub mod wks;
use {Type, Error};
pub use self::a::Record as A;
pub use self::aaaa::Record as Aaaa;
pub use self::cname::Record as Cname;
pub use self::mx::Record as Mx;
pub use self::ns::Record as Ns;
pub use self::nsec::Record as Nsec;
pub use self::opt::Record as Opt;
pub use self::ptr::Record as Ptr;
pub use self::soa::Record as Soa;
pub use self::srv::Record as Srv;
pub use self::txt::Record as Txt;
pub type RDataResult<'a> = Result<RData<'a>, Error>;
/// The enumeration that represents known types of DNS resource records data
#[derive(Debug)]
pub enum RData<'a> {
A(A),
AAAA(Aaaa),
CNAME(Cname<'a>),
MX(Mx<'a>),
NS(Ns<'a>),
PTR(Ptr<'a>),
SOA(Soa<'a>),
SRV(Srv<'a>),
TXT(Txt<'a>),
/// Anything that can't be parsed yet
Unknown(&'a [u8]),
}
pub (crate) trait Record<'a> {
const TYPE: isize;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a>;
}
impl<'a> RData<'a> {
/// Parse an RR data and return RData enumeration
pub fn parse(typ: Type, rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a> {
match typ {
Type::A => A::parse(rdata, original),
Type::AAAA => Aaaa::parse(rdata, original),
Type::CNAME => Cname::parse(rdata, original),
Type::NS => Ns::parse(rdata, original),
Type::MX => Mx::parse(rdata, original),
Type::PTR => Ptr::parse(rdata, original),
Type::SOA => Soa::parse(rdata, original),
Type::SRV => Srv::parse(rdata, original),
Type::TXT => Txt::parse(rdata, original),
_ => Ok(RData::Unknown(rdata)),
}
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 9;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,92 +0,0 @@
use {Name, Error};
use byteorder::{BigEndian, ByteOrder};
#[derive(Debug, Clone, Copy)]
pub struct Record<'a> {
pub preference: u16,
pub exchange: Name<'a>,
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 15;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
if rdata.len() < 3 {
return Err(Error::WrongRdataLength);
}
let record = Record {
preference: BigEndian::read_u16(&rdata[..2]),
exchange: Name::scan(&rdata[2..], original)?,
};
Ok(super::RData::MX(record))
}
}
#[cfg(test)]
mod test {
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
use super::*;
#[test]
fn parse_response() {
let response = b"\xe3\xe8\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
\x05gmail\x03com\x00\x00\x0f\x00\x01\xc0\x0c\x00\x0f\x00\x01\
\x00\x00\x04|\x00\x1b\x00\x05\rgmail-smtp-in\x01l\x06google\xc0\
\x12\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\x00\t\x00\
\n\x04alt1\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\
\x00\t\x00(\x04alt4\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\
\x00\x04|\x00\t\x00\x14\x04alt2\xc0)\xc0\x0c\x00\x0f\
\x00\x01\x00\x00\x04|\x00\t\x00\x1e\x04alt3\xc0)";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 58344,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 5,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::MX);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..],
"gmail.com");
assert_eq!(packet.answers.len(), 5);
let items = vec![
( 5, "gmail-smtp-in.l.google.com"),
(10, "alt1.gmail-smtp-in.l.google.com"),
(40, "alt4.gmail-smtp-in.l.google.com"),
(20, "alt2.gmail-smtp-in.l.google.com"),
(30, "alt3.gmail-smtp-in.l.google.com"),
];
for i in 0..5 {
assert_eq!(&packet.answers[i].name.to_string()[..],
"gmail.com");
assert_eq!(packet.answers[i].cls, C::IN);
assert_eq!(packet.answers[i].ttl, 1148);
match *&packet.answers[i].data {
RData::MX( Record { preference, exchange }) => {
assert_eq!(preference, items[i].0);
assert_eq!(exchange.to_string(), (items[i].1).to_string());
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}
}

View File

@ -1,88 +0,0 @@
use Name;
#[derive(Debug, Clone, Copy)]
pub struct Record<'a>(pub Name<'a>);
impl<'a> ToString for Record<'a> {
#[inline]
fn to_string(&self) -> String {
self.0.to_string()
}
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 2;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
let name = Name::scan(rdata, original)?;
let record = Record(name);
Ok(super::RData::NS(record))
}
}
#[cfg(test)]
mod test {
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
#[test]
fn parse_response() {
let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x00\
\x03www\x05skype\x03com\x00\x00\x01\x00\x01\
\xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
\x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
\x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
\x72\x03\x6e\x65\x74\x00\
\xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
\x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
\xc0\x42";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 19184,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 1,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
assert_eq!(packet.answers.len(), 1);
assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 3600);
match packet.answers[0].data {
RData::CNAME(cname) => {
assert_eq!(&cname.0.to_string()[..], "livecms.trafficmanager.net");
}
ref x => panic!("Wrong rdata {:?}", x),
}
assert_eq!(packet.nameservers.len(), 1);
assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
assert_eq!(packet.nameservers[0].cls, C::IN);
assert_eq!(packet.nameservers[0].ttl, 120275);
match packet.nameservers[0].data {
RData::NS(ns) => {
assert_eq!(&ns.0.to_string()[..], "g.gtld-servers.net");
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 47;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 10;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,18 +0,0 @@
/// RFC 6891 OPT RR
#[derive(Debug)]
pub struct Record<'a> {
pub udp: u16,
pub extrcode: u8,
pub version: u8,
pub flags: u16,
pub data: super::RData<'a>,
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 41;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,74 +0,0 @@
use Name;
#[derive(Debug, Clone, Copy)]
pub struct Record<'a>(pub Name<'a>);
impl<'a> ToString for Record<'a> {
#[inline]
fn to_string(&self) -> String {
self.0.to_string()
}
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 12;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
let name = Name::scan(rdata, original)?;
let record = Record(name);
Ok(super::RData::PTR(record))
}
}
#[cfg(test)]
mod test {
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
#[test]
fn parse_response() {
let response = b"\x53\xd6\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
\x0269\x0293\x0275\x0272\x07in-addr\x04arpa\x00\
\x00\x0c\x00\x01\
\xc0\x0c\x00\x0c\x00\x01\x00\x01\x51\x80\x00\x1e\
\x10pool-72-75-93-69\x07verizon\x03net\x00";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 21462,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::PTR);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "69.93.75.72.in-addr.arpa");
assert_eq!(packet.answers.len(), 1);
assert_eq!(&packet.answers[0].name.to_string()[..], "69.93.75.72.in-addr.arpa");
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 86400);
match packet.answers[0].data {
RData::PTR(name) => {
assert_eq!(&name.0.to_string()[..], "pool-72-75-93-69.verizon.net");
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}

View File

@ -1,101 +0,0 @@
use {Name, Error};
use byteorder::{BigEndian, ByteOrder};
/// The SOA (Start of Authority) record
#[derive(Debug, Clone, Copy)]
pub struct Record<'a> {
pub primary_ns: Name<'a>,
pub mailbox: Name<'a>,
pub serial: u32,
pub refresh: u32,
pub retry: u32,
pub expire: u32,
pub minimum_ttl: u32,
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 6;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
let mut pos = 0;
let primary_name_server = try!(Name::scan(rdata, original));
pos += primary_name_server.byte_len();
let mailbox = try!(Name::scan(&rdata[pos..], original));
pos += mailbox.byte_len();
if rdata[pos..].len() < 20 {
return Err(Error::WrongRdataLength);
}
let record = Record {
primary_ns: primary_name_server,
mailbox: mailbox,
serial: BigEndian::read_u32(&rdata[pos..(pos+4)]),
refresh: BigEndian::read_u32(&rdata[(pos+4)..(pos+8)]),
retry: BigEndian::read_u32(&rdata[(pos+8)..(pos+12)]),
expire: BigEndian::read_u32(&rdata[(pos+12)..(pos+16)]),
minimum_ttl: BigEndian::read_u32(&rdata[(pos+16)..(pos+20)]),
};
Ok(super::RData::SOA(record))
}
}
#[cfg(test)]
mod test {
use {Packet, Header};
use Opcode::*;
use ResponseCode::NameError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
#[test]
fn parse_response() {
let response = b"\x9f\xc5\x85\x83\x00\x01\x00\x00\x00\x01\x00\x00\
\x0edlkfjkdjdslfkj\x07youtube\x03com\x00\x00\x01\x00\x01\
\xc0\x1b\x00\x06\x00\x01\x00\x00\x2a\x30\x00\x1e\xc0\x1b\
\x05admin\xc0\x1b\x77\xed\x2a\x73\x00\x00\x51\x80\x00\x00\
\x0e\x10\x00\x00\x3a\x80\x00\x00\x2a\x30";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 40901,
query: false,
opcode: StandardQuery,
authoritative: true,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NameError,
questions: 1,
answers: 0,
nameservers: 1,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::A);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "dlkfjkdjdslfkj.youtube.com");
assert_eq!(packet.answers.len(), 0);
assert_eq!(packet.nameservers.len(), 1);
assert_eq!(&packet.nameservers[0].name.to_string()[..], "youtube.com");
assert_eq!(packet.nameservers[0].cls, C::IN);
assert_eq!(packet.nameservers[0].multicast_unique, false);
assert_eq!(packet.nameservers[0].ttl, 10800);
match packet.nameservers[0].data {
RData::SOA(ref soa_rec) => {
assert_eq!(&soa_rec.primary_ns.to_string()[..], "youtube.com");
assert_eq!(&soa_rec.mailbox.to_string()[..], "admin.youtube.com");
assert_eq!(soa_rec.serial, 2012031603);
assert_eq!(soa_rec.refresh, 20864);
assert_eq!(soa_rec.retry, 3600);
assert_eq!(soa_rec.expire, 14976);
assert_eq!(soa_rec.minimum_ttl, 10800);
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}

View File

@ -1,102 +0,0 @@
use {Name, Error};
use byteorder::{BigEndian, ByteOrder};
#[derive(Debug, Clone, Copy)]
pub struct Record<'a> {
pub priority: u16,
pub weight: u16,
pub port: u16,
pub target: Name<'a>,
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 33;
fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> {
if rdata.len() < 7 {
return Err(Error::WrongRdataLength);
}
let record = Record {
priority: BigEndian::read_u16(&rdata[..2]),
weight: BigEndian::read_u16(&rdata[2..4]),
port: BigEndian::read_u16(&rdata[4..6]),
target: Name::scan(&rdata[6..], original)?,
};
Ok(super::RData::SRV(record))
}
}
#[cfg(test)]
mod test {
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
use super::*;
#[test]
fn parse_response() {
let response = b"[\xd9\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
\x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01\
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00 \x00\x05\x00\x00\
\x14\x95\x0bxmpp-server\x01l\x06google\x03com\x00\xc0\x0c\x00!\
\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\x14\x95\
\x04alt3\x0bxmpp-server\x01l\x06google\x03com\x00\
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
\x14\x95\x04alt1\x0bxmpp-server\x01l\x06google\x03com\x00\
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
\x14\x95\x04alt2\x0bxmpp-server\x01l\x06google\x03com\x00\
\xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
\x14\x95\x04alt4\x0bxmpp-server\x01l\x06google\x03com\x00";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 23513,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 5,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::SRV);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..],
"_xmpp-server._tcp.gmail.com");
assert_eq!(packet.answers.len(), 5);
let items = vec![
(5, 0, 5269, "xmpp-server.l.google.com"),
(20, 0, 5269, "alt3.xmpp-server.l.google.com"),
(20, 0, 5269, "alt1.xmpp-server.l.google.com"),
(20, 0, 5269, "alt2.xmpp-server.l.google.com"),
(20, 0, 5269, "alt4.xmpp-server.l.google.com"),
];
for i in 0..5 {
assert_eq!(&packet.answers[i].name.to_string()[..],
"_xmpp-server._tcp.gmail.com");
assert_eq!(packet.answers[i].cls, C::IN);
assert_eq!(packet.answers[i].ttl, 900);
match *&packet.answers[i].data {
RData::SRV(Record { priority, weight, port, target }) => {
assert_eq!(priority, items[i].0);
assert_eq!(weight, items[i].1);
assert_eq!(port, items[i].2);
assert_eq!(target.to_string(), (items[i].3).to_string());
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}
}

View File

@ -1,125 +0,0 @@
use Error;
#[derive(Debug, Clone)]
pub struct Record<'a> {
bytes: &'a [u8],
}
#[derive(Debug)]
pub struct RecordIter<'a> {
bytes: &'a [u8],
}
impl<'a> Iterator for RecordIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> {
if self.bytes.len() >= 1 {
let len = self.bytes[0] as usize;
debug_assert!(self.bytes.len() >= len+1);
let (head, tail) = self.bytes[1..].split_at(len);
self.bytes = tail;
return Some(head);
}
return None;
}
}
impl<'a> Record<'a> {
// Returns iterator over text chunks
pub fn iter(&self) -> RecordIter<'a> {
RecordIter {
bytes: self.bytes,
}
}
}
impl<'a> super::Record<'a> for Record<'a> {
const TYPE: isize = 16;
fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
// Just a quick check that record is valid
let len = rdata.len();
if len < 1 {
return Err(Error::WrongRdataLength);
}
let mut pos = 0;
while pos < len {
let rdlen = rdata[pos] as usize;
pos += 1;
if len < rdlen + pos {
return Err(Error::WrongRdataLength);
}
pos += rdlen;
}
Ok(super::RData::TXT(Record {
bytes: rdata,
}))
}
}
#[cfg(test)]
mod test {
use std::str::from_utf8;
use {Packet, Header};
use Opcode::*;
use ResponseCode::NoError;
use QueryType as QT;
use QueryClass as QC;
use Class as C;
use RData;
#[test]
fn parse_response_multiple_strings() {
let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
\x08facebook\x03com\x00\x00\x10\x00\x01\
\xc0\x0c\x00\x10\x00\x01\x00\x01\x51\x3d\x00\x23\
\x15\x76\x3d\x73\x70\x66\x31\x20\x72\x65\x64\x69\
\x72\x65\x63\x74\x3d\x5f\x73\x70\x66\x2e\
\x0c\x66\x61\x63\x65\x62\x6f\x6f\x6b\x2e\x63\x6f\x6d";
let packet = Packet::parse(response).unwrap();
assert_eq!(packet.header, Header {
id: 1573,
query: false,
opcode: StandardQuery,
authoritative: false,
truncated: false,
recursion_desired: true,
recursion_available: true,
authenticated_data: false,
checking_disabled: false,
response_code: NoError,
questions: 1,
answers: 1,
nameservers: 0,
additional: 0,
});
assert_eq!(packet.questions.len(), 1);
assert_eq!(packet.questions[0].qtype, QT::TXT);
assert_eq!(packet.questions[0].qclass, QC::IN);
assert_eq!(&packet.questions[0].qname.to_string()[..], "facebook.com");
assert_eq!(packet.answers.len(), 1);
assert_eq!(&packet.answers[0].name.to_string()[..], "facebook.com");
assert_eq!(packet.answers[0].multicast_unique, false);
assert_eq!(packet.answers[0].cls, C::IN);
assert_eq!(packet.answers[0].ttl, 86333);
match packet.answers[0].data {
RData::TXT(ref text) => {
assert_eq!(text.iter()
.map(|x| from_utf8(x).unwrap())
.collect::<Vec<_>>()
.concat(), "v=spf1 redirect=_spf.facebook.com");
// also assert boundaries are kept
assert_eq!(text.iter().collect::<Vec<_>>(),
["v=spf1 redirect=_spf.".as_bytes(),
"facebook.com".as_bytes()]);
}
ref x => panic!("Wrong rdata {:?}", x),
}
}
}

View File

@ -1,11 +0,0 @@
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Record;
impl<'a> super::Record<'a> for Record {
const TYPE: isize = 11;
fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> {
unimplemented!();
}
}

View File

@ -1,50 +0,0 @@
use {QueryType, QueryClass, Name, Class, Header, RData};
use rdata::opt;
/// Parsed DNS packet
#[derive(Debug)]
#[allow(missing_docs)] // should be covered by spec
pub struct Packet<'a> {
pub header: Header,
pub questions: Vec<Question<'a>>,
pub answers: Vec<ResourceRecord<'a>>,
pub nameservers: Vec<ResourceRecord<'a>>,
pub additional: Vec<ResourceRecord<'a>>,
/// Optional Pseudo-RR
/// When present it is sent as an RR in the additional section. In this RR
/// the `class` and `ttl` fields store max udp packet size and flags
/// respectively. To keep `ResourceRecord` clean we store the OPT record
/// here.
pub opt: Option<opt::Record<'a>>,
}
/// A parsed chunk of data in the Query section of the packet
#[derive(Debug)]
#[allow(missing_docs)] // should be covered by spec
pub struct Question<'a> {
pub qname: Name<'a>,
/// Whether or not we prefer unicast responses.
/// This is used in multicast DNS.
pub prefer_unicast: bool,
pub qtype: QueryType,
pub qclass: QueryClass,
}
/// A single DNS record
///
/// We aim to provide whole range of DNS records available. But as time is
/// limited we have some types of packets which are parsed and other provided
/// as unparsed slice of bytes.
#[derive(Debug)]
#[allow(missing_docs)] // should be covered by spec
pub struct ResourceRecord<'a> {
pub name: Name<'a>,
/// Whether or not the set of resource records is fully contained in the
/// packet, or whether there will be more resource records in future
/// packets. Only used for multicast DNS.
pub multicast_unique: bool,
pub cls: Class,
pub ttl: u32,
pub data: RData<'a>,
}

View File

@ -1,44 +0,0 @@
commands:
cargo: !Command
description: Run any cargo command
container: ubuntu
run: [cargo]
make: !Command
description: Build the library
container: ubuntu
run: [cargo, build]
test: !Command
description: Run the tests
container: ubuntu
environ:
RUST_BACKTRACE: 1
run: [cargo, test]
_bulk: !Command
description: Run `bulk` command (for version bookkeeping)
container: ubuntu
run: [bulk]
containers:
ubuntu:
setup:
- !Ubuntu xenial
- !UbuntuUniverse
- !Install [ca-certificates, build-essential, vim]
- !TarInstall
url: "https://static.rust-lang.org/dist/rust-1.28.0-x86_64-unknown-linux-gnu.tar.gz"
script: "./install.sh --prefix=/usr \
--components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo"
- &bulk !Tar
url: "https://github.com/tailhook/bulk/releases/download/v0.4.11/bulk-v0.4.11.tar.gz"
sha256: b718bb8448e726690c94d98d004bf7575f7a429106ec26ad3faf11e0fd9a7978
path: /
environ:
HOME: /work/target
USER: pc

View File

@ -43,7 +43,6 @@ storage = { path = "../../../../storage/rust" }
bookmark_sync = { path = "../../../components/places/bookmark_sync", optional = true }
shift_or_euc_c = "0.1.0"
audio_thread_priority = "0.19.1"
mdns_service = { path="../../../../media/mtransport/mdns_service" }
[build-dependencies]
rustc_version = "0.2"

View File

@ -52,8 +52,6 @@ extern crate arrayvec;
extern crate audio_thread_priority;
extern crate mdns_service;
use std::boxed::Box;
use std::env;
use std::ffi::{CStr, CString};