Skip to content

Commit

Permalink
cc: retrieve blocklists after uncloaking domain names
Browse files Browse the repository at this point in the history
  • Loading branch information
ignoramous committed Jan 4, 2023
1 parent aca3bb2 commit 7de2bd9
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/core/svc.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async function systemReady() {
services.prefilter = new DNSPrefilter();
services.dnsCacheHandler = new DNSCacheResponder(bw, cache);
services.dnsResolver = new DNSResolver(bw, cache);
services.commandControl = new CommandControl(bw, lp);
services.commandControl = new CommandControl(bw, services.dnsResolver, lp);

services.ready = true;

Expand Down
121 changes: 85 additions & 36 deletions src/plugins/command-control/cc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@
import * as cfg from "../../core/cfg.js";
import * as util from "../../commons/util.js";
import * as rdnsutil from "../rdns-util.js";
import * as dnsutil from "../../commons/dnsutil.js";
import * as pres from "../plugin-response.js";
import { flagsToTags, tagsToFlags } from "@serverless-dns/trie/stamp.js";
import * as token from "../users/auth-token.js";
import { BlocklistFilter } from "../rethinkdns/filter.js";
import { LogPusher } from "../observability/log-pusher.js";
import { BlocklistWrapper } from "../rethinkdns/main.js";
import { DNSResolver } from "../dns-op/dns-op.js";

export class CommandControl {
constructor(blocklistWrapper, logPusher) {
constructor(blocklistWrapper, resolver, logPusher) {
this.latestTimestamp = rdnsutil.bareTimestampFrom(cfg.timestamp());
this.log = log.withTags("CommandControl");
/** @type {BlocklistWrapper} */
this.bw = blocklistWrapper;
/** @type {DNSResolver} */
this.resolver = resolver;
/** @type {LogPusher} */
this.lp = logPusher;
this.cmds = new Set([
Expand All @@ -46,7 +50,7 @@ export class CommandControl {
if (util.isGetRequest(ctx.request)) {
return await this.commandOperation(
ctx.rxid,
ctx.request.url,
ctx.request,
ctx.isDnsMsg,
ctx.userAuth,
ctx.lid
Expand Down Expand Up @@ -80,12 +84,13 @@ export class CommandControl {

/**
* @param {string} rxid
* @param {Request} request
* @param {Request} req
* @param {boolean} isDnsCmd
* @param {token.Outcome} auth
* @param {string} lid
*/
async commandOperation(rxid, url, isDnsCmd, auth, lid) {
async commandOperation(rxid, req, isDnsCmd, auth, lid) {
const url = req.url;
let response = pres.emptyResponse();

try {
Expand Down Expand Up @@ -117,7 +122,9 @@ export class CommandControl {

this.log.d(rxid, url, "processing... cmd/flag", command, b64UserFlag);

// blocklistFilter may not to have been setup, so set it up
// resolver may not have been setup, so set it up
await this.resolver.lazyInit();
// blocklistFilter may not have been setup, so set it up
await this.bw.init(rxid, /* force-wait */ true);
const blf = this.bw.getBlocklistFilter();
const isBlfSetup = rdnsutil.isBlocklistFilterSetup(blf);
Expand All @@ -132,14 +139,21 @@ export class CommandControl {
response.data.httpResponse = b64ToList(queryString, blf);
} else if (command === "dntolist") {
// convert names to blocklists (tags)
response.data.httpResponse = domainNameToList(
response.data.httpResponse = await domainNameToList(
rxid,
this.resolver,
req,
queryString,
blf,
this.latestTimestamp
);
} else if (command === "dntouint") {
// convert names to flags
response.data.httpResponse = domainNameToUint(queryString, blf);
response.data.httpResponse = domainNameToUint(
this.resolver,
queryString,
blf
);
} else if (command === "search") {
// redirect to the search page with blockstamp (b64) preloaded
response.data.httpResponse = searchRedirect(b64UserFlag);
Expand Down Expand Up @@ -268,46 +282,80 @@ async function analytics(lp, reqUrl, auth, lid) {
}

/**
* @param {string} rxid
* @param {DNSResolver} resolver
* @param {Request} req
* @param {string} queryString
* @param {BlocklistFilter} blocklistFilter
* @param {number} latestTimestamp
* @returns {Response}
* @returns {Promise<Response>}
*/
function domainNameToList(queryString, blocklistFilter, latestTimestamp) {
async function domainNameToList(
rxid,
resolver,
req,
queryString,
blocklistFilter,
latestTimestamp
) {
const domainName = queryString.get("dn") || "";
const r = {
domainName: domainName,
version: latestTimestamp,
list: {},
};

const searchResult = blocklistFilter.lookup(domainName);
if (!searchResult) {
return jsonResponse(r);
}

// ex: max.rethinkdns.com/dntolist?dn=google.com
// res: { "domainName": "google.com",
// "version":"1655223903366",
// "list": { "google.com": {
// "NUI": {
// "value":149,
// "uname":"NUI",
// "vname":"No Google",
// "group":"privacy",
// "subg":"",
// "url":"https://raw.githubuserc...",
// "show":1,
// "entries":304
// }
// }
// },
// ...
// }
for (const entry of searchResult) {
const list = flagsToTags(entry[1]);
const listDetail = blocklistFilter.extract(list);
r.list[entry[0]] = listDetail;
// qid for doh is always 0
const qid = 0;
const qs = [
{
type: "A",
name: domainName,
},
];
// only doh truly works across runtimes, workers/fastly/node/deno
const forcedoh = true;
const query = dnsutil.mkQ(qid, qs);
const querypacket = dnsutil.decode(query);
const rmax = resolver.determineDohResolvers(resolver.ofMax(), forcedoh);
const res = await resolver.resolveDnsUpstream(
rxid,
req,
rmax,
query,
querypacket
);
const ans = await res.arrayBuffer();
const anspacket = dnsutil.decode(ans);
const ansdomains = dnsutil.extractDomains(anspacket);

for (const d of ansdomains) {
const searchResult = blocklistFilter.lookup(d);
if (!searchResult) continue;

// ex: max.rethinkdns.com/dntolist?dn=google.com
// res: { "domainName": "google.com",
// "version":"1655223903366",
// "list": { "google.com": {
// "NUI": {
// "value":149,
// "uname":"NUI",
// "vname":"No Google",
// "group":"privacy",
// "subg":"",
// "url":"https://raw.githubuserc...",
// "show":1,
// "entries":304
// }
// }
// },
// ...
// }
for (const entry of searchResult) {
const list = flagsToTags(entry[1]);
const listDetail = blocklistFilter.extract(list);
r.list[entry[0]] = listDetail;
}
}

return jsonResponse(r);
Expand All @@ -319,6 +367,7 @@ function domainNameToList(queryString, blocklistFilter, latestTimestamp) {
* @returns {Response}
*/
function domainNameToUint(queryString, blocklistFilter) {
// TODO: resolve the query like in domainNameToList
const domainName = queryString.get("dn") || "";
const r = {
domainName: domainName,
Expand Down

0 comments on commit 7de2bd9

Please sign in to comment.