diff --git a/src/routes/convert.ts b/src/routes/convert.ts index 6266f24..4ee2292 100644 --- a/src/routes/convert.ts +++ b/src/routes/convert.ts @@ -8,9 +8,15 @@ import net from "node:net"; function isPrivateIP(ip: string): boolean { // IPv6 loopback/unspecified if (ip === "::1" || ip === "::") return true; + + // IPv6 link-local (fe80::/10) + if (ip.toLowerCase().startsWith("fe8") || ip.toLowerCase().startsWith("fe9") || + ip.toLowerCase().startsWith("fea") || ip.toLowerCase().startsWith("feb")) return true; + // IPv4-mapped IPv6 if (ip.startsWith("::ffff:")) ip = ip.slice(7); if (!net.isIPv4(ip)) return false; + const parts = ip.split(".").map(Number); if (parts[0] === 0) return true; // 0.0.0.0/8 if (parts[0] === 10) return true; // 10.0.0.0/8 @@ -160,7 +166,7 @@ convertRouter.post("/url", async (req: Request & { acquirePdfSlot?: () => Promis try { const { address } = await dns.lookup(parsed.hostname); if (isPrivateIP(address)) { - res.status(400).json({ error: "URL resolves to private/reserved IP" }); + res.status(400).json({ error: "URL resolves to a private/internal IP address" }); return; } } catch {