Skip to content

Commit

Permalink
registry (on play.html) shows domain status
Browse files Browse the repository at this point in the history
The domains newly do the following things:
- resolve the status
- recheck for the status if the status is not active
- resolve Zone

There is a workaround for the resolve DoH, as WASM produces an error for subdomains & dohjs does not support SVCB lookups.
  • Loading branch information
MathJud committed Aug 24, 2024
1 parent 8bf6b61 commit 4c90e99
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 65 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"cSpell.words": [
"dnssec",
"keypair",
"Nameserver",
"rrsig",
"sig0namectl",
"wireformat"
Expand Down
134 changes: 110 additions & 24 deletions demo/playground/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,24 @@ class Dns {
constructor(domain_name, key, on_initialized) {
// domain name
this.domain = domain_name;
this.doh_domain = '1.1.1.1';
this.doh_url = 'https://1.1.1.1/dns-query';
this.doh_method = 'POST';
this.zone = null;
this.status = 'undefined';

// keys related to this domain
this.keys = [];
if (key) {
this.keys.push(key)
}

// set initalization flags
// set initialization flags
this.dnssec_enabled = false;
this.wasm = false;
this.initialized = false;
this.initialized_callbacks = [];


// create the resolver
this.resolver = new doh.DohResolver(this.doh_url);

Expand All @@ -42,12 +45,17 @@ class Dns {
if (typeof on_initialized === 'function') {
on_initialized()
}

// find DoH server
await this.get_doh();

// check key status
this.check_key_status()
}

/// read the record types from dns of a domain
/// and return an object
query(query_domain, record_type, callback, referrer) {
console.log('--- query(): create and populate query structure')
async query(query_domain, record_type, callback, referrer) {
const query = doh.makeQuery(query_domain, record_type);
// we always want to query with DNSSEC enabled
// TODO: Could this create a problem in the future, if a Nameserver is not
Expand All @@ -61,26 +69,26 @@ class Dns {
options: []
}]
}
console.log(JSON.stringify(query));
console.log();
console.log(query.flags & doh.dnsPacket.AUTHENTIC_DATA);

console.log('query: ' + query_domain + ' ' + record_type)
console.log(query)
let query_result =
doh.sendDohMsg(query, this.doh_url, this.doh_method).then(response => {
let result = [];

response.answers.forEach(ans => {
if (ans.type == record_type) {
result.push(ans.data);
}
});
console.log('--- query(): response');
console.log(JSON.stringify(response));
// return object
callback(result, referrer);
});

return query_result;
await doh.sendDohMsg(query, this.doh_url, this.doh_method);
console.log(query_result)
let result = [];

query_result.answers.forEach(ans => {
if (ans.type == record_type) {
result.push(ans.data);
}
});

// return object
if (typeof callback === Function) {
callback(result, referrer);
}

return result;
}

/// read the query response & look for SOA record from:
Expand All @@ -98,8 +106,7 @@ class Dns {
}
}

for (let i = 0; i < query_result.authorities.length; i++) {
const auth = query_result.authorities[i];
for (const auth of query_result.authorities) {
if (auth.type == 'SOA') {
console.log('SOA found in authorities: ' + auth.name);
return auth.name;
Expand All @@ -109,6 +116,44 @@ class Dns {
return Promise.reject('no Zone found for ' + query_domain);
}

/// get DoH endpoint
///
/// TODO: This is just a workaround, waiting for the blockers to be fixed.
/// FIXME: The WASM DoH function throws an error when querying for subdomains.
/// FIXME: The dohjs library returns an empty answer section for SVCB queries.
async get_doh() {
if (this.domain.endsWith('zenr.io')) {
this.doh_domain = 'doh.zenr.io';
this.doh_url = 'https://doh.zenr.io/dns_query';
}
if (this.domain.endsWith('beta.freifunk.net')) {
this.doh_domain = 'doh.zenr.io';
this.doh_url = 'https://doh.zenr.io/dns_query';
}

return;

// -----------------------------------------------------
// The following code needs fixing of the blockers first
let domain_parts = this.domain.split('.')
let doh = null
for (let i = 0; domain_parts.length - i >= 2; i++) {
// construct query domain
let query_domain = '_dns'
for (let j = i; j < domain_parts.length; j++) {
query_domain += '.'
query_domain += domain_parts[j]
}
// query SVCB record
const query_result = await this.query(query_domain, 'SVCB');

// check result
console.log(
'i: ' + i + ', domain_parts.length - i' + (domain_parts.length - i))
}
return doh
}

/// check if an RRSIG record is present for a specific domain
async check_rrsig(query_domain) {
const query_result = await this.resolver.query(query_domain, 'RRSIG');
Expand All @@ -121,6 +166,47 @@ class Dns {

return Promise.reject('something went wrong');
}

/// check key status
///
/// The domain status is decided out of the key status.
/// The domain status can have one of the following values:
///
/// - undefined: status has not yet been checked
/// - registering: key is in the _signal domain and waiting for approval
/// - active: key is registered under the domain
/// - inactive: this key is not registered and not in _signal domain
async check_key_status() {
// request key status updates
let promises = [];
for (const key of this.keys) {
if (key.active === null || key.waiting == null ||
(key.active === false && key.waiting === false)) {
// check if we have all information
if (this.zone === null) {
return
}

const status = key.check_status(this.zone, this.doh_domain);

promises.push(status)
}
}
Promise.all(promises)

// define domain status
let domain_status = 'inactive'
for (const key of this.keys) {
if (key.active === true) {
domain_status = 'active';
break
}
if (key.waiting === true) {
domain_status = 'registering'
}
}
this.status = domain_status;
}
}


Expand Down
26 changes: 20 additions & 6 deletions demo/playground/domains.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ class Domains {
}
this.domains = [];
this.initialized = false;
this.recheck_status = false;

// add domains
if (Array.isArray(domain_array)) {
for (let i = 0; i < domain_array.length; i++) {
const domain_name = domain_array[i];
for (const domain_name of domain_array) {
this.add_domain(domain_name)
}
}
Expand All @@ -44,14 +44,29 @@ class Domains {
keys_updated(keys_array) {
// auto add keys
if (this.options.key_auto_add) {
for (let i = 0; i < keys_array.length; i++) {
const key = keys_array[i];
for (const key of keys_array) {
const domain_item = this.get_domain(key.domain)

// add domain if it does not exist
if (!domain_item) {
this.add_domain(key.domain, key)
}
else {
// check if key exists in already existing domain
let key_exists = false;
for (const domain_key of domain_item.keys) {
if (domain_key.filename === key.filename) {
key_exists = true;
break
}
}
// add key if it doesn't exist
if (key_exists === false) {
domain_item.keys.push(key);
domain_item.check_key_status();
this.recheck_status = true;
}
}
}
}

Expand Down Expand Up @@ -89,8 +104,7 @@ class Domains {
/// and returns the Dns object if found.
/// The function returns `null` if no domain was found.
get_domain(domain_name) {
for (let i = 0; i < this.domains.length; i++) {
const dns = this.domains[i];
for (const dns of this.domains) {
if (domain_name === dns.domain) {
return dns
}
Expand Down
107 changes: 83 additions & 24 deletions demo/playground/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ class Keys {
return Promise.reject(error)
})

for (let i = 0; i < keys.length; i++) {
const filename = keys[i].Name;
const domain = this.domain_from_filename(filename);
const key = new Key(domain, filename);
this.keys.push(key)
let promises = [];
for (const key of keys) {
promises.push(this.update_key(key));
}

// wait for all promises to resolve
await Promise.all(promises)

// send keystore ready event
const event = new CustomEvent('keys_ready')
window.dispatchEvent(event)
Expand All @@ -42,27 +43,59 @@ class Keys {
const keys = await this.get_keys().catch(error => {
console.error(error)
return Promise.reject(error)
})
});

// TODO: check & update status of new keys
for (let i = 0; i < keys.length; i++) {
if (!this.key_exists(keys[i])) {
const filename = keys[i].Name;
const domain = this.domain_from_filename(filename);
const key = new Key(domain, filename);
this.keys.push(key)
}

let promises = [];
for (const key of keys) {
promises.push(this.update_key(key));
}

// send keystore ready event
const event = new CustomEvent('keys_updated')
window.dispatchEvent(event)
// wait for all promises to resolve
await Promise.all(promises).then((values) => {
let key_updated = false;
for (const value of values) {
if (value === true) {
key_updated = true
}

// send keystore ready event
if (key_updated === true) {
const event = new CustomEvent('keys_updated')
window.dispatchEvent(event)
}
}
})
}

/// Update a Single Key
///
/// This method takes a keystore key object as input.
///
/// - check status of the key
/// - create a key object
/// - fill in the key object into the keys object
async update_key(key) {
// check if key exists
if (this.key_exists(key.Name) === false) {
// create new key object
const filename = key.Name;
const domain = this.domain_from_filename(filename);
const my_key = new Key(domain, filename);

// push key to keys
this.keys.push(my_key)

return true;
}

return false;
}

/// check if key already exists
key_exists(filename) {
for (let i = 0; i < this.keys.length; i++) {
if (this.keys[i] === filename) {
for (const key of this.keys) {
if (key.filename === filename) {
return true
}
}
Expand Down Expand Up @@ -117,12 +150,38 @@ class Key {
/// construct the key
///
/// providing it a domain name and optionally a key filename
constructor(domain, filename) {
this.domain = domain
if (filename) {
this.filename = filename;
constructor(domain, filename, public_key) {
this.domain = domain;
this.filename = filename;
this.public_key = public_key;
this.active = null;
this.waiting = null;
}

/// TODO: check status of key
///
/// this function requires the zone domain and the domain of the DoH (DNS over
/// Https)
async check_status(zone, doh_domain) {
// check status of key
console.log(
'key.check_status ' + this.domain + ' ' + zone + ' ' + doh_domain)
let status =
await window.goFuncs.checkKeyStatus(this.filename, zone, doh_domain);

if (status.KeyRRExists === 'true') {
this.active = true;
} else {
this.active = false;
}
if (status.QueuePTRExists === 'true') {
this.waiting = true;
} else {
this.waiting = false;
}

// TODO: check status of key
console.log(
'status received: ' + this.domain + ' active: ' + this.active +
' waiting: ' + this.waiting)
}
}
Loading

0 comments on commit 4c90e99

Please sign in to comment.