Updates to Holesail

This commit is contained in:
Raven Scott
2026-05-27 21:55:25 -04:00
parent d57433d3e0
commit 1d1bf83e2b
2 changed files with 70 additions and 20 deletions
+69 -19
View File
@@ -18,6 +18,12 @@ const MAX_CERT_CACHE_SIZE = parseInt(process.env.MAX_CERT_CACHE_SIZE || '1000',
// Store internal domains in module-level variable so it can be updated dynamically
let internalDomainsList = ['p2ns.admin']; // Default to p2ns.admin
function isConnectionRefusedError(err) {
if (!err) return false;
const msg = err.message || '';
return err.code === 'ECONNREFUSED' || msg.includes('ECONNREFUSED');
}
// Helper function to set certificate in cache with size limit enforcement
function setCertCache(domain, cert) {
// If cache is at limit, remove oldest entries (simple FIFO - remove first key)
@@ -405,29 +411,66 @@ async function setupProxyServer() {
method: req.method,
headers: req.headers,
};
const supportsAutomaticRetry = ['GET', 'HEAD', 'OPTIONS'].includes((req.method || 'GET').toUpperCase());
const timeoutMs = parseInt(process.env.INTERNAL_PROXY_TIMEOUT_MS || '12000', 10);
const proxyRequest = http.request(options, (proxyRes) => {
const headers = {};
for (const [key, value] of Object.entries(proxyRes.headers)) {
const lowerKey = key.toLowerCase();
if (lowerKey !== 'strict-transport-security' && lowerKey !== 'hsts') {
headers[key] = value;
const sendProxyRequest = (attempt = 0) => {
const proxyRequest = http.request(options, (proxyRes) => {
const headers = {};
for (const [key, value] of Object.entries(proxyRes.headers)) {
const lowerKey = key.toLowerCase();
if (lowerKey !== 'strict-transport-security' && lowerKey !== 'hsts') {
headers[key] = value;
}
}
setSecurityHeaders(res);
res.writeHead(proxyRes.statusCode, headers);
proxyRes.pipe(res, { end: true });
});
proxyRequest.setTimeout(timeoutMs, () => {
proxyRequest.destroy(new Error('Internal proxy request timeout'));
});
proxyRequest.on('error', async (err) => {
logError('Proxy', `Error proxying request for ${domain}: ${err.message}`);
if (isConnectionRefusedError(err)) {
try {
logWarn('Proxy', `Connection refused for ${domain}, restarting Holesail client ${localIP}:${state.internalPort}`);
await restartHolesailClient(domain, hash, localIP, state.internalPort);
} catch (restartErr) {
logError('Proxy', `Failed to restart Holesail client after ECONNREFUSED for ${domain}: ${restartErr.message}`);
}
if (supportsAutomaticRetry && attempt === 0 && !res.headersSent) {
logInfo('Proxy', `Retrying proxy request once for ${domain} after Holesail restart`);
sendProxyRequest(1);
return;
}
if (!res.headersSent) {
setSecurityHeaders(res);
res.writeHead(503);
res.end('Service Unavailable: reconnecting tunnel, retry in a moment');
}
return;
}
if (!res.headersSent) {
setSecurityHeaders(res);
res.writeHead(500);
res.end('Internal Server Error');
}
});
if (supportsAutomaticRetry) {
proxyRequest.end();
} else {
req.pipe(proxyRequest, { end: true });
}
setSecurityHeaders(res);
res.writeHead(proxyRes.statusCode, headers);
proxyRes.pipe(res, { end: true });
});
};
proxyRequest.on('error', (err) => {
logError('Proxy', `Error proxying request for ${domain}: ${err.message}`);
setSecurityHeaders(res);
res.writeHead(500);
res.end('Internal Server Error');
});
req.pipe(proxyRequest, { end: true });
sendProxyRequest(0);
} catch (err) {
logError('Proxy', `Failed to handle request: ${err.message}`);
res.writeHead(500);
@@ -569,6 +612,13 @@ async function setupProxyServer() {
clientReq.on('error', (err) => {
logError('Proxy', `WebSocket proxy error for ${domain}: ${err.message}`);
if (isConnectionRefusedError(err)) {
restartHolesailClient(domain, hash, localIP, state.internalPort).catch((restartErr) => {
logError('Proxy', `Failed to restart WebSocket Holesail client after ECONNREFUSED for ${domain}: ${restartErr.message}`);
});
socket.end('HTTP/1.1 503 Service Unavailable\r\n\r\n');
return;
}
socket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
});
} catch (err) {