diff --git a/server/routes.ts b/server/routes.ts index d2f90fb..7da8293 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -5,6 +5,7 @@ import { db } from "./db"; import { setupAuth, requireRole } from "./auth"; import { z } from "zod"; import { eq } from "drizzle-orm"; +import { getCurrentIpAddress, getCurrentIpv6Address } from "./utils/ip-utils"; import { insertDomainSchema, insertDnsRecordSchema, @@ -169,7 +170,40 @@ export async function registerRoutes(app: Express): Promise { console.log(`API endpoint: Fetching DNS records for domain: ${domainId}`); const records = await storage.getDnsRecordsByDomain(domainId); console.log(`API endpoint: Retrieved ${records.length} DNS records from storage`); - res.json(records); + + // Process records to show current IP for auto IP records + const processedRecords = await Promise.all(records.map(async (record) => { + // For A records with auto IP enabled, fetch the current IP + if (record.isAutoIP && (record.type === 'A' || record.type === 'AAAA')) { + try { + // Get the appropriate IP address based on record type + let currentIp = null; + if (record.type === 'A') { + currentIp = await getCurrentIpAddress(); + } else if (record.type === 'AAAA') { + currentIp = await getCurrentIpv6Address(); + } + + if (currentIp) { + console.log(`Found current IP for auto record ${record.id}: ${currentIp}`); + // Create a new object to avoid modifying the original record + return { + ...record, + // Store the actual IP in the response for display purposes + currentIp: currentIp, + // Keep content as is - the UI will show currentIp if isAutoIP is true + }; + } + } catch (ipError) { + console.error(`Error getting current IP for record ${record.id}:`, ipError); + } + } + + // Return the record unmodified if it's not auto IP or if there was an error + return record; + })); + + res.json(processedRecords); } catch (error) { console.error("Error fetching DNS records:", error); res.status(500).json({ @@ -188,6 +222,31 @@ export async function registerRoutes(app: Express): Promise { return res.status(404).json({ message: "DNS record not found" }); } + // For A/AAAA records with auto IP enabled, fetch the current IP address + if (record.isAutoIP && (record.type === 'A' || record.type === 'AAAA')) { + try { + // Get the appropriate IP address based on record type + let currentIp = null; + if (record.type === 'A') { + currentIp = await getCurrentIpAddress(); + } else if (record.type === 'AAAA') { + currentIp = await getCurrentIpv6Address(); + } + + if (currentIp) { + console.log(`Found current IP for auto record ${record.id}: ${currentIp}`); + // Create a new object to avoid modifying the original record + return res.json({ + ...record, + // Store the actual IP in the response for display purposes + currentIp: currentIp + }); + } + } catch (ipError) { + console.error(`Error getting current IP for record ${record.id}:`, ipError); + } + } + res.json(record); } catch (error) { console.error("Error fetching DNS record:", error); diff --git a/server/utils/ip-utils.ts b/server/utils/ip-utils.ts new file mode 100644 index 0000000..1895f71 --- /dev/null +++ b/server/utils/ip-utils.ts @@ -0,0 +1,69 @@ +import fetch from 'node-fetch'; + +/** + * Gets the current public IP address of the server + * Uses multiple services for redundancy + */ +export async function getCurrentIpAddress(): Promise { + const ipServices = [ + 'https://api.ipify.org', + 'https://ifconfig.me/ip', + 'https://icanhazip.com', + 'https://ipecho.net/plain' + ]; + + // Try each service in sequence until we get a valid response + for (const service of ipServices) { + try { + console.log(`Attempting to get IP address from ${service}`); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 5000); + + const response = await fetch(service, { signal: controller.signal }); + clearTimeout(timeoutId); + + if (response.ok) { + const ip = (await response.text()).trim(); + console.log(`Got IP address: ${ip} from ${service}`); + + // Basic validation - IP should be a string with numbers and dots + if (ip && /^[0-9.]+$/.test(ip)) { + return ip; + } + } + } catch (error) { + console.error(`Error getting IP from ${service}:`, error); + // Continue to the next service + } + } + + console.error('Failed to get IP address from any service'); + return null; +} + +/** + * Gets the current IPv6 address (if available) + */ +export async function getCurrentIpv6Address(): Promise { + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 5000); + + const response = await fetch('https://ipv6.icanhazip.com', { signal: controller.signal }); + clearTimeout(timeoutId); + + if (response.ok) { + const ip = (await response.text()).trim(); + console.log(`Got IPv6 address: ${ip}`); + + // Basic validation for IPv6 format + if (ip && ip.includes(':')) { + return ip; + } + } + } catch (error) { + console.error('Error getting IPv6 address:', error); + } + + return null; +} \ No newline at end of file