import * as plugins from './plugins.js';
import { type IIpcDnsQuestion, type TDnsQueryResponseKind } from './classes.rustdnsbridge.js';
export interface IDnsServerOptions {
    httpsKey: string;
    httpsCert: string;
    httpsPort: number;
    udpPort: number;
    /** Port for TCP DNS queries. Defaults to udpPort. */
    tcpPort?: number;
    dnssecZone: string;
    /** Zones for which unanswered queries receive authoritative negative responses. */
    authoritativeZones?: string[];
    udpBindInterface?: string;
    /** IP to bind TCP DNS. Defaults to udpBindInterface or 0.0.0.0. */
    tcpBindInterface?: string;
    httpsBindInterface?: string;
    manualUdpMode?: boolean;
    manualTcpMode?: boolean;
    manualHttpsMode?: boolean;
    primaryNameserver?: string;
    enableLocalhostHandling?: boolean;
}
export interface DnsAnswer {
    name: string;
    type: string;
    class: string | number;
    ttl: number;
    data: any;
}
export interface IDnsQuestion {
    name: string;
    type: string;
    class?: string;
}
/**
 * Whether a handler's answers may claim zone authority.
 *
 * - `authoritative` (default): the handler only answers for names that fall
 *   inside a configured `authoritativeZones` entry. Matches outside every
 *   configured zone are suppressed rather than answered, because answering
 *   them would publish a claim of authority over a delegation this server
 *   does not hold.
 * - `non-authoritative`: the handler may answer for any matching name, but
 *   the response never carries the AA bit and is never DNSSEC-signed. This is
 *   the mode for split-horizon and private-route overlays.
 */
export type TDnsHandlerAuthority = 'authoritative' | 'non-authoritative';
export interface IDnsHandlerOptions {
    /** Defaults to `authoritative`. */
    authority?: TDnsHandlerAuthority;
    /** Opaque owner label, for attribution and bulk teardown. */
    owner?: string;
}
/** Handle returned by `registerHandler`, identifying exactly one registration. */
export interface IDnsHandlerRegistration {
    readonly id: string;
    readonly domainPattern: string;
    readonly recordTypes: readonly string[];
    readonly authority: TDnsHandlerAuthority;
    readonly owner?: string;
    /** Remove exactly this registration. Returns false if already removed. */
    unregister(): boolean;
}
/** Read-only view of a registration, for introspection. */
export interface IDnsHandlerInfo {
    readonly id: string;
    readonly domainPattern: string;
    readonly recordTypes: readonly string[];
    readonly authority: TDnsHandlerAuthority;
    readonly owner?: string;
}
export interface IDnsHandler {
    id: string;
    domainPattern: string;
    recordTypes: string[];
    authority: TDnsHandlerAuthority;
    owner?: string;
    handler: (question: IDnsQuestion) => DnsAnswer | null;
}
/** A handler match that was withheld because it fell outside every zone. */
export interface IDnsSuppressedHandler {
    questionName: string;
    questionType: string;
    domainPattern: string;
    handlerId: string;
    owner?: string;
}
interface LetsEncryptOptions {
    email?: string;
    staging?: boolean;
    certDir?: string;
}
export interface IDnsQueryCompletedEvent {
    /** The original questions from the query */
    questions: IIpcDnsQuestion[];
    /** Whether any handler answered the query */
    answered: boolean;
    /** The outcome actually sent on the wire */
    responseKind: TDnsQueryResponseKind;
    /** The authoritative zone the questions resolved into, if any */
    authorityZone: string | null;
    /** Handler matches withheld because they fell outside every zone */
    suppressedHandlers: IDnsSuppressedHandler[];
    /** How long handler resolution took (ms) */
    responseTimeMs: number;
    /** Timestamp of the query */
    timestamp: number;
}
/**
 * Emitted whenever a query is declined, or an answer is withheld. Every
 * refusal is attributable: without this a misregistered handler is invisible.
 */
export interface IDnsQueryRefusedEvent {
    questions: IIpcDnsQuestion[];
    responseKind: TDnsQueryResponseKind;
    authorityZone: string | null;
    suppressedHandlers: IDnsSuppressedHandler[];
    timestamp: number;
}
export declare class DnsServer extends plugins.events.EventEmitter {
    private options;
    private bridge;
    private handlers;
    private handlerIdCounter;
    /** Patterns already warned about, so a hot loop cannot flood the log. */
    private warnedOutOfZonePatterns;
    /** Stable for the lifetime of this server, so the apex SOA does not churn. */
    private readonly soaSerial;
    private bridgeSpawned;
    private httpsServer;
    private udpServer;
    private tcpServer;
    constructor(options: IDnsServerOptions);
    /**
     * Register a DNS handler for a domain pattern and record types.
     *
     * Registering a handler is not by itself a claim of authority. Answers only
     * carry the AA bit when the queried name falls inside a configured
     * `authoritativeZones` entry. A handler left at the default
     * `authoritative` mode whose match falls outside every configured zone is
     * suppressed rather than answered; pass `{ authority: 'non-authoritative' }`
     * to serve such names deliberately, without claiming authority for them.
     *
     * @returns a handle identifying exactly this registration.
     */
    registerHandler(domainPattern: string, recordTypes: string[], handler: (question: IDnsQuestion) => DnsAnswer | null, options?: IDnsHandlerOptions): IDnsHandlerRegistration;
    /**
     * Unregister every handler registered for this exact pattern whose record
     * types cover all of `recordTypes`.
     *
     * This is deliberately coarse and cannot distinguish between two consumers
     * that registered the same pattern. Prefer the handle returned by
     * `registerHandler`, or `unregisterHandlerById` / `unregisterHandlersByOwner`.
     */
    unregisterHandler(domainPattern: string, recordTypes: string[]): boolean;
    /**
     * Remove exactly one registration, by the id from `registerHandler`.
     * Leaves every other handler on the same pattern untouched.
     */
    unregisterHandlerById(handlerId: string): boolean;
    /**
     * Remove every registration made with the given `owner`.
     * @returns the number of handlers removed.
     */
    unregisterHandlersByOwner(owner: string): number;
    /** Every currently registered handler, for introspection and leak checks. */
    listHandlers(): IDnsHandlerInfo[];
    /**
     * Start the DNS server.
     */
    start(): Promise<void>;
    /**
     * Stop the DNS server.
     */
    stop(): Promise<void>;
    /**
     * Initialize servers (no-op with Rust bridge, kept for API compatibility).
     */
    initializeServers(): void;
    /**
     * Initialize UDP server (no-op with Rust bridge).
     */
    initializeUdpServer(): void;
    /**
     * Initialize HTTPS server (no-op with Rust bridge).
     */
    initializeHttpsServer(): void;
    /**
     * Handle a raw TCP socket for HTTPS/DoH.
     * In Rust mode, this is not directly supported — use processRawDnsPacket instead.
     */
    handleHttpsSocket(socket: plugins.net.Socket): void;
    /**
     * Handle a UDP message manually.
     */
    handleUdpMessage(msg: Buffer, rinfo: plugins.dgram.RemoteInfo, responseCallback?: (response: Buffer, rinfo: plugins.dgram.RemoteInfo) => void): void;
    /**
     * Process a raw DNS packet asynchronously via Rust bridge.
     *
     * Pass `transport: 'udp'` when the response will be sent as a UDP
     * datagram: the response is then truncated (TC bit set) to the client's
     * advertised EDNS0 payload size, or 512 bytes without EDNS0. Without it,
     * no size bound is applied — correct for TCP and DoH framing.
     */
    processRawDnsPacketAsync(packet: Buffer, transport?: 'udp' | 'tcp'): Promise<Buffer>;
    /**
     * Retrieve SSL certificate for specified domains using Let's Encrypt
     */
    retrieveSslCertificate(domainNames: string[], options?: LetsEncryptOptions): Promise<{
        cert: string;
        key: string;
        success: boolean;
    }>;
    /**
     * Filter domains to include only those the server is authoritative for.
     */
    filterAuthorizedDomains(domainNames: string[]): string[];
    /**
     * Resolve a DNS query event from Rust using TypeScript handlers.
     *
     * Authority is decided by configuration, never by the presence of a
     * handler. A handler match is only served as an authoritative answer when
     * the queried name falls inside a configured authoritative zone.
     */
    private resolveQuery;
    /** Strip the trailing root dot and case, so matching is RFC 4343 correct. */
    private normalizeName;
    /** Configured authoritative zones, most specific first. */
    private normalizedAuthoritativeZones;
    /** The most specific configured zone containing `name`, if any. */
    private zoneForName;
    /**
     * Whether a pattern is anchored inside a configured authoritative zone.
     * Used only to warn at registration time; query-time authority is always
     * decided from the actual question name, never from this.
     */
    private patternCanMatchAuthoritativeZone;
    /**
     * Whether something this server serves exists strictly below `name`.
     * Such a name is an empty non-terminal: it holds no records of its own,
     * but names beneath it exist, so the correct negative answer for it is
     * NODATA — never NXDOMAIN, which would deny the whole subtree (RFC 8020).
     *
     * Descendants exist when a configured authoritative zone sits below the
     * name (its apex exists by configuration), or when a handler pattern is
     * anchored below it (literal `.name` suffix, or a wildcard that matches a
     * probe label). Mid-label wildcard patterns cannot be fully inverted by
     * this check; see readme.hints.md.
     */
    private nameHasCoveredDescendants;
    /** The SOA this server publishes at the apex of a zone it is authoritative for. */
    private buildApexSoaAnswer;
    /** Resolve the most specific configured authority shared by all questions. */
    private getAuthorityZone;
    private getDnsRecordValueForChallenge;
    private isValidIpAddress;
    private isAuthorizedForDomain;
}
export {};
