diff --git a/src/commons/mod.rs b/src/commons/mod.rs index e74a494..cecb307 100644 --- a/src/commons/mod.rs +++ b/src/commons/mod.rs @@ -129,6 +129,7 @@ pub fn is_yggdrasil_record(record: &DnsRecord) -> bool { DnsRecord::AAAA { addr, .. } => return is_yggdrasil(&IpAddr::from(*addr)), DnsRecord::SRV { .. } => {} DnsRecord::OPT { .. } => {} + DnsRecord::TLSA { .. } => {} } true } diff --git a/src/dns/protocol.rs b/src/dns/protocol.rs index 73a08f3..81fdf7b 100644 --- a/src/dns/protocol.rs +++ b/src/dns/protocol.rs @@ -39,6 +39,7 @@ pub enum QueryType { AAAA, // 28 SRV, // 33 OPT, // 41 + TLSA, // 52 } impl QueryType { @@ -55,6 +56,7 @@ impl QueryType { QueryType::AAAA => 28, QueryType::SRV => 33, QueryType::OPT => 41, + QueryType::TLSA => 52, } } @@ -70,6 +72,7 @@ impl QueryType { 28 => QueryType::AAAA, 33 => QueryType::SRV, 41 => QueryType::OPT, + 52 => QueryType::TLSA, _ => QueryType::UNKNOWN(num), } } @@ -169,6 +172,14 @@ pub enum DnsRecord { flags: u32, data: String }, // 41 + TLSA { + domain: String, + certificate_usage: u8, + selector: u8, + matching_type: u8, + data: Vec, + ttl: TransientTtl + }, // 52 } impl DnsRecord { @@ -281,6 +292,16 @@ impl DnsRecord { Ok(DnsRecord::OPT { packet_len: class, flags: ttl, data }) } + QueryType::TLSA => { + let certificate_usage = buffer.read()?; + let selector = buffer.read()?; + let matching_type = buffer.read()?; + let cur_pos = buffer.pos(); + let data_len = data_len - 3; + let data = buffer.get_range(cur_pos, data_len as usize)?.to_vec(); + buffer.step(data_len as usize)?; + Ok(DnsRecord::TLSA { domain, certificate_usage, selector, matching_type, data, ttl: TransientTtl(ttl) }) + } QueryType::UNKNOWN(_) => { buffer.step(data_len as usize)?; @@ -422,6 +443,20 @@ impl DnsRecord { buffer.write_u8(*b)?; } } + DnsRecord::TLSA { ref domain, certificate_usage, selector, matching_type, ref data, ttl: TransientTtl(ttl) } => { + buffer.write_qname(domain)?; + buffer.write_u16(QueryType::TLSA.to_num())?; + buffer.write_u16(1)?; + buffer.write_u32(ttl)?; + buffer.write_u16((data.len() + 3) as u16)?; + buffer.write_u8(certificate_usage)?; + buffer.write_u8(selector)?; + buffer.write_u8(matching_type)?; + + for b in data { + buffer.write_u8(*b)?; + } + } DnsRecord::OPT { packet_len, flags, ref data } => { buffer.write_u8(0)?; buffer.write_u16(QueryType::OPT.to_num())?; @@ -454,6 +489,7 @@ impl DnsRecord { DnsRecord::SOA { .. } => QueryType::SOA, DnsRecord::TXT { .. } => QueryType::TXT, DnsRecord::OPT { .. } => QueryType::OPT, + DnsRecord::TLSA { .. } => QueryType::TLSA, } } @@ -469,7 +505,8 @@ impl DnsRecord { | DnsRecord::UNKNOWN { ref domain, .. } | DnsRecord::SOA { ref domain, .. } | DnsRecord::TXT { ref domain, .. } => Some(domain.clone()), - DnsRecord::OPT { .. } => None, + DnsRecord::OPT { .. } + | DnsRecord::TLSA { .. } => None, } } @@ -490,6 +527,10 @@ impl DnsRecord { Some(result) }, DnsRecord::UNKNOWN { ref domain, .. } => Some(domain.clone()), + DnsRecord::TLSA { ref domain, certificate_usage, selector, matching_type, ref data, .. } => { + let data = crate::commons::to_hex(data); + Some(format!("{} {} {} {} {}", domain, certificate_usage, selector, matching_type, &data)) + }, DnsRecord::OPT { .. } => None, } } @@ -506,6 +547,7 @@ impl DnsRecord { | DnsRecord::UNKNOWN { ttl: TransientTtl(ttl), .. } | DnsRecord::SOA { ttl: TransientTtl(ttl), .. } | DnsRecord::TXT { ttl: TransientTtl(ttl), .. } => ttl, + | DnsRecord::TLSA { ttl: TransientTtl(ttl), .. } => ttl, DnsRecord::OPT { .. } => 0 } } diff --git a/src/dns/resolve.rs b/src/dns/resolve.rs index 044ef2f..5607542 100644 --- a/src/dns/resolve.rs +++ b/src/dns/resolve.rs @@ -54,6 +54,7 @@ pub trait DnsResolver { for filter in context.filters.iter() { if let Some(packet) = filter.lookup(qname, qtype) { + context.cache.store(&packet.answers)?; return Ok(packet); } } diff --git a/src/dns/server.rs b/src/dns/server.rs index 91d6c60..fa02a92 100644 --- a/src/dns/server.rs +++ b/src/dns/server.rs @@ -107,6 +107,7 @@ pub fn execute_query(context: Arc, request: &DnsPacket) -> DnsPac let question = &request.questions[0]; packet.questions.push(question.clone()); + log::trace!("Resolving: {}, type {:?}", &question.name, &question.qtype); let mut resolver = context.create_resolver(Arc::clone(&context)); let res_code = match resolver.resolve(&question.name, question.qtype, request.header.recursion_desired) { diff --git a/src/webview/index.html b/src/webview/index.html index c85382d..4996fa3 100644 --- a/src/webview/index.html +++ b/src/webview/index.html @@ -388,6 +388,7 @@ + diff --git a/src/webview/scripts.js b/src/webview/scripts.js index 3e945a4..5814be7 100644 --- a/src/webview/scripts.js +++ b/src/webview/scripts.js @@ -81,7 +81,7 @@ function refreshRecordsList() { function showNewRecordDialog() { var button_positive = document.getElementById("new_record_positive_button"); button_positive.onclick = function() { - checkRecord(get_record_from_dialog()); + checkRecord(getRecordFromDialog()); }; var button_negative = document.getElementById("new_record_negative_button"); @@ -95,7 +95,7 @@ function showNewRecordDialog() { dialog.className = "modal is-active"; } -function get_record_from_dialog() { +function getRecordFromDialog() { var record_name = document.getElementById("record_name").value.toLowerCase(); var record_type = document.getElementById("record_type").value; var record_ttl = parseInt(document.getElementById("record_ttl").value); @@ -112,6 +112,12 @@ function get_record_from_dialog() { var record_weight = parseInt(document.getElementById("record_weight").value); var record_port = parseInt(document.getElementById("record_port").value); return { type: record_type, domain: record_name, ttl: record_ttl, priority: record_priority, weight: record_weight, port: record_port, host: record_data } + } else if (record_type == "TLSA") { + var certificate_usage = parseInt(document.getElementById("record_priority").value); + var selector = parseInt(document.getElementById("record_weight").value); + var matching_type = parseInt(document.getElementById("record_port").value); + record_data = hexToBytes(record_data); + return { type: record_type, domain: record_name, ttl: record_ttl, certificate_usage: certificate_usage, selector: selector, matching_type: matching_type, data: record_data } } return { type: record_type, domain: record_name, ttl: record_ttl, addr: record_data } } @@ -266,7 +272,7 @@ function checkRecord(data) { function recordOkay(okay) { if (okay) { - addRecord(get_record_from_dialog()); // It will refresh list + addRecord(getRecordFromDialog()); // It will refresh list var dialog = document.getElementById("new_record_dialog"); dialog.className = "modal"; } else { @@ -654,4 +660,12 @@ function selectKey(index, event) { function keySelected(index) { currentSelectedKey = index; refreshKeysMenu(); +} + +// Convert a hex string to a byte array +function hexToBytes(hex) { + for (var bytes = [], c = 0; c < hex.length; c += 2) { + bytes.push(parseInt(hex.substr(c, 2), 16)); + } + return bytes; } \ No newline at end of file