Add license checks to JobScheduler and AuthoritativeDNSServer

This commit is contained in:
Owen
2026-09-10 14:13:58 -04:00
parent 7537d0d792
commit 94f2e579d1
2 changed files with 41 additions and 0 deletions
@@ -17,6 +17,7 @@ import { certificateService } from "./certificate-service";
import { privateConfig as config } from "#private/lib/config";
import { dnsValidator } from "./dns-validator";
import { domainReverifier } from "./domain-reverifier";
import license from "#private/license/license";
// Backstop for runExclusive: no single job's own internal timeouts (e.g.
// certificate-service's per-cert issuance timeout) are relied on here. This
@@ -44,6 +45,12 @@ export class JobScheduler {
label: string
): () => Promise<void> {
return async () => {
if (!(await license.isUnlocked())) {
logger.debug(
`Skipping ${label} tick - license is not subscribed`
);
return;
}
if (state.active) {
logger.debug(
`Skipping ${label} tick - previous run still in progress`
+34
View File
@@ -33,6 +33,7 @@ import * as dnsResolver from "dns";
import logger from "@server/logger";
import { listExitNodes } from "../exitNodes";
import { rateLimitService } from "../rateLimit";
import license from "#private/license/license";
type DNSRecord = {
id: number;
@@ -57,6 +58,13 @@ export class AuthoritativeDNSServer {
private allDomains: Set<string> = new Set();
private domainRefreshInterval: NodeJS.Timeout | null = null;
// Cached license/subscription status. license.isUnlocked() does a DB
// round-trip on every call, so it can't be checked per-query on a UDP
// server that may see very high query volume - instead it's polled on
// the same cadence as the domain set refresh and read from memory here.
private isLicensed: boolean = false;
private licenseRefreshInterval: NodeJS.Timeout | null = null;
// Cache for per-queryName zone resolution and SOA records
private authoritativeDomainCache: NodeCache = new NodeCache({
stdTTL: 300,
@@ -121,6 +129,15 @@ export class AuthoritativeDNSServer {
return;
}
if (!this.isLicensed) {
logger.debug(
"Refusing DNS query - license is not subscribed"
);
// REFUSED (rcode=5) indicates a policy refusal by this nameserver.
this.sendResponse(packet, [], rinfo, false, 5, []);
return;
}
const question = packet.questions[0];
const dnsRateLimit = config.getRawConfig().dns!.rate_limit;
@@ -1027,6 +1044,15 @@ export class AuthoritativeDNSServer {
}
}
private async refreshLicenseStatus(): Promise<void> {
try {
this.isLicensed = await license.isUnlocked();
} catch (error) {
logger.error("Failed to refresh license status:", error);
this.isLicensed = false;
}
}
public async start(): Promise<void> {
await this.loadAllDomains();
this.domainRefreshInterval = setInterval(() => {
@@ -1035,6 +1061,11 @@ export class AuthoritativeDNSServer {
);
}, 60_000);
await this.refreshLicenseStatus();
this.licenseRefreshInterval = setInterval(() => {
this.refreshLicenseStatus();
}, 60_000);
return new Promise((resolve, reject) => {
this.server.bind(this.port, (err?: Error) => {
if (err) {
@@ -1050,6 +1081,9 @@ export class AuthoritativeDNSServer {
if (this.domainRefreshInterval) {
clearInterval(this.domainRefreshInterval);
}
if (this.licenseRefreshInterval) {
clearInterval(this.licenseRefreshInterval);
}
return new Promise((resolve) => {
this.server.close(() => {
logger.info("DNS server stopped");