protect MSNTV2 proxy a little bit

This commit is contained in:
zefie
2026-05-03 09:33:46 -04:00
parent 1cf8032be4
commit 94e8ecb60a
2 changed files with 52 additions and 2 deletions

View File

@@ -49,9 +49,21 @@ class WTVMSNTV2 {
}; };
} }
get maxProxyResponseBytes() {
const defaultMb = 16;
const configuredMb = parseFloat(this.service_config.max_response_size || defaultMb);
const mb = Number.isFinite(configuredMb) && configuredMb > 0 ? configuredMb : defaultMb;
return Math.max(1, mb) * 1024 * 1024;
}
isAllowedUserAgent(userAgent) {
if (!userAgent || typeof userAgent !== 'string') return false;
return /MSNTV|WebTV/i.test(userAgent);
}
listen(port, host = '0.0.0.0') { listen(port, host = '0.0.0.0') {
this.server.listen(port, host); this.server.listen(port, host);
console.log(` * MSNTV2 Proxy listening on ${host}:${port}`); console.log(` * Started MSNTV2 Proxy on port ${port}`);
return this.server; return this.server;
} }
@@ -123,6 +135,12 @@ class WTVMSNTV2 {
handleData(socket, chunk) { handleData(socket, chunk) {
socket.buffer = Buffer.concat([socket.buffer, chunk]); socket.buffer = Buffer.concat([socket.buffer, chunk]);
if (socket.buffer.length > parseFloat(this.minisrv_config.services[service_name].max_response_size || 128) * 1024 * 1024) {
this.writeError(socket, 413, 'Request Entity Too Large');
socket.destroy();
return;
}
const headerEnd = socket.buffer.indexOf('\r\n\r\n'); const headerEnd = socket.buffer.indexOf('\r\n\r\n');
if (headerEnd < 0) return; if (headerEnd < 0) return;
@@ -176,6 +194,15 @@ class WTVMSNTV2 {
Object.assign(request_headers, headers); Object.assign(request_headers, headers);
const userAgent = request_headers['User-Agent'] || request_headers['user-agent'] || '';
if (!this.isAllowedUserAgent(userAgent)) {
if (this.service_config.show_verbose_errors || this.minisrv_config.config.verbosity >= 3) {
console.warn('[WTV-MSNTV2] unsupported User-Agent rejected:', userAgent || '<none>');
}
this.writeError(socket, 403, 'Forbidden', request_headers);
return;
}
const verbose = this.service_config.show_verbose_errors || this.minisrv_config.config.verbosity >= 3; const verbose = this.service_config.show_verbose_errors || this.minisrv_config.config.verbosity >= 3;
if (verbose) { if (verbose) {
console.log('[WTV-MSNTV2] incoming request:', requestLine); console.log('[WTV-MSNTV2] incoming request:', requestLine);
@@ -1741,12 +1768,22 @@ class WTVMSNTV2 {
maxBodyLength: 1024 * 1024 * 64 maxBodyLength: 1024 * 1024 * 64
}; };
const maxResponseBytes = this.maxProxyResponseBytes;
const proxyReq = agent.request(options, (res) => { const proxyReq = agent.request(options, (res) => {
const verbose = this.service_config.show_verbose_errors || this.minisrv_config.config.verbosity >= 3; const verbose = this.service_config.show_verbose_errors || this.minisrv_config.config.verbosity >= 3;
if (verbose) { if (verbose) {
console.log('[WTV-MSNTV2] upstream response:', res.statusCode, res.statusMessage); console.log('[WTV-MSNTV2] upstream response:', res.statusCode, res.statusMessage);
console.log('[WTV-MSNTV2] upstream response headers:', JSON.stringify(res.headers)); console.log('[WTV-MSNTV2] upstream response headers:', JSON.stringify(res.headers));
} }
const contentLength = parseInt(res.headers['content-length'] || res.headers['Content-Length'] || '0', 10) || 0;
if (contentLength > 0 && contentLength > maxResponseBytes) {
console.warn(` * MSNTV2 upstream response exceeds configured max_response_size (${contentLength} bytes > ${maxResponseBytes} bytes), aborting`);
res.destroy();
this.writeError(socket, 413, 'Payload Too Large', request_headers);
return;
}
const responseHeaders = []; const responseHeaders = [];
const closeClientConnection = this._shouldCloseClientConnection(request_headers); const closeClientConnection = this._shouldCloseClientConnection(request_headers);
responseHeaders.push(`HTTP/1.1 ${res.statusCode} ${res.statusMessage}`); responseHeaders.push(`HTTP/1.1 ${res.statusCode} ${res.statusMessage}`);
@@ -1759,7 +1796,19 @@ class WTVMSNTV2 {
responseHeaders.push(''); responseHeaders.push('');
responseHeaders.push(''); responseHeaders.push('');
this.writeToSocket(socket, responseHeaders.join('\r\n')); this.writeToSocket(socket, responseHeaders.join('\r\n'));
res.on('data', (chunk) => this.writeToSocket(socket, chunk));
let totalResponseBytes = 0;
res.on('data', (chunk) => {
totalResponseBytes += chunk.length;
if (totalResponseBytes > maxResponseBytes) {
console.warn(` * MSNTV2 proxy response exceeded ${maxResponseBytes} bytes, cutting off connection.`);
res.destroy();
socket.destroy();
return;
}
this.writeToSocket(socket, chunk);
});
res.on('end', () => { res.on('end', () => {
if (!socket.destroyed && closeClientConnection) this.endSocket(socket); if (!socket.destroyed && closeClientConnection) this.endSocket(socket);
}); });

View File

@@ -505,6 +505,7 @@
"handler_module": "WTV-MSNTV2", "handler_module": "WTV-MSNTV2",
"handler_handles_port": true, "handler_handles_port": true,
"servicevault_dir": "msntv2", "servicevault_dir": "msntv2",
"max_response_size": 64, // Megabytes
"intercept_urls": [ "intercept_urls": [
{ {
"match": "headwaiter.trusted.msntv.msn.com", "match": "headwaiter.trusted.msntv.msn.com",