mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-12 05:51:30 +02:00
Add license checks to JobScheduler and AuthoritativeDNSServer
This commit is contained in:
@@ -17,6 +17,7 @@ import { certificateService } from "./certificate-service";
|
|||||||
import { privateConfig as config } from "#private/lib/config";
|
import { privateConfig as config } from "#private/lib/config";
|
||||||
import { dnsValidator } from "./dns-validator";
|
import { dnsValidator } from "./dns-validator";
|
||||||
import { domainReverifier } from "./domain-reverifier";
|
import { domainReverifier } from "./domain-reverifier";
|
||||||
|
import license from "#private/license/license";
|
||||||
|
|
||||||
// Backstop for runExclusive: no single job's own internal timeouts (e.g.
|
// Backstop for runExclusive: no single job's own internal timeouts (e.g.
|
||||||
// certificate-service's per-cert issuance timeout) are relied on here. This
|
// certificate-service's per-cert issuance timeout) are relied on here. This
|
||||||
@@ -44,6 +45,12 @@ export class JobScheduler {
|
|||||||
label: string
|
label: string
|
||||||
): () => Promise<void> {
|
): () => Promise<void> {
|
||||||
return async () => {
|
return async () => {
|
||||||
|
if (!(await license.isUnlocked())) {
|
||||||
|
logger.debug(
|
||||||
|
`Skipping ${label} tick - license is not subscribed`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (state.active) {
|
if (state.active) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Skipping ${label} tick - previous run still in progress`
|
`Skipping ${label} tick - previous run still in progress`
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import * as dnsResolver from "dns";
|
|||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { listExitNodes } from "../exitNodes";
|
import { listExitNodes } from "../exitNodes";
|
||||||
import { rateLimitService } from "../rateLimit";
|
import { rateLimitService } from "../rateLimit";
|
||||||
|
import license from "#private/license/license";
|
||||||
|
|
||||||
type DNSRecord = {
|
type DNSRecord = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -57,6 +58,13 @@ export class AuthoritativeDNSServer {
|
|||||||
private allDomains: Set<string> = new Set();
|
private allDomains: Set<string> = new Set();
|
||||||
private domainRefreshInterval: NodeJS.Timeout | null = null;
|
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
|
// Cache for per-queryName zone resolution and SOA records
|
||||||
private authoritativeDomainCache: NodeCache = new NodeCache({
|
private authoritativeDomainCache: NodeCache = new NodeCache({
|
||||||
stdTTL: 300,
|
stdTTL: 300,
|
||||||
@@ -121,6 +129,15 @@ export class AuthoritativeDNSServer {
|
|||||||
return;
|
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 question = packet.questions[0];
|
||||||
const dnsRateLimit = config.getRawConfig().dns!.rate_limit;
|
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> {
|
public async start(): Promise<void> {
|
||||||
await this.loadAllDomains();
|
await this.loadAllDomains();
|
||||||
this.domainRefreshInterval = setInterval(() => {
|
this.domainRefreshInterval = setInterval(() => {
|
||||||
@@ -1035,6 +1061,11 @@ export class AuthoritativeDNSServer {
|
|||||||
);
|
);
|
||||||
}, 60_000);
|
}, 60_000);
|
||||||
|
|
||||||
|
await this.refreshLicenseStatus();
|
||||||
|
this.licenseRefreshInterval = setInterval(() => {
|
||||||
|
this.refreshLicenseStatus();
|
||||||
|
}, 60_000);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.server.bind(this.port, (err?: Error) => {
|
this.server.bind(this.port, (err?: Error) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -1050,6 +1081,9 @@ export class AuthoritativeDNSServer {
|
|||||||
if (this.domainRefreshInterval) {
|
if (this.domainRefreshInterval) {
|
||||||
clearInterval(this.domainRefreshInterval);
|
clearInterval(this.domainRefreshInterval);
|
||||||
}
|
}
|
||||||
|
if (this.licenseRefreshInterval) {
|
||||||
|
clearInterval(this.licenseRefreshInterval);
|
||||||
|
}
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.server.close(() => {
|
this.server.close(() => {
|
||||||
logger.info("DNS server stopped");
|
logger.info("DNS server stopped");
|
||||||
|
|||||||
Reference in New Issue
Block a user