76 lines
2.5 KiB
JavaScript
Executable File
76 lines
2.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
// Example proxy server that listens on :::8877 and only allows HTTPS connections to example.com.
|
|
// Set `GEMINI_SANDBOX_PROXY_COMMAND=scripts/example-proxy.js` to run proxy alongside sandbox
|
|
// Test via `curl https://example.com` inside sandbox (in shell mode or via shell tool)
|
|
|
|
import http from 'http';
|
|
import net from 'net';
|
|
import { URL } from 'url';
|
|
import console from 'console';
|
|
|
|
const PROXY_PORT = 8877;
|
|
const ALLOWED_DOMAINS = ['example.com', 'googleapis.com'];
|
|
const ALLOWED_PORT = '443';
|
|
|
|
const server = http.createServer((req, res) => {
|
|
// Deny all requests other than CONNECT for HTTPS
|
|
console.log(
|
|
`[PROXY] Denying non-CONNECT request for: ${req.method} ${req.url}`,
|
|
);
|
|
res.writeHead(405, { 'Content-Type': 'text/plain' });
|
|
res.end('Method Not Allowed');
|
|
});
|
|
|
|
server.on('connect', (req, clientSocket, head) => {
|
|
// req.url will be in the format "hostname:port" for a CONNECT request.
|
|
const { port, hostname } = new URL(`http://${req.url}`);
|
|
|
|
console.log(`[PROXY] Intercepted CONNECT request for: ${hostname}:${port}`);
|
|
|
|
if (
|
|
ALLOWED_DOMAINS.some(
|
|
(domain) => hostname == domain || hostname.endsWith(`.${domain}`),
|
|
) &&
|
|
port === ALLOWED_PORT
|
|
) {
|
|
console.log(`[PROXY] Allowing connection to ${hostname}:${port}`);
|
|
|
|
// Establish a TCP connection to the original destination.
|
|
const serverSocket = net.connect(port, hostname, () => {
|
|
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
// Create a tunnel by piping data between the client and the destination server.
|
|
serverSocket.write(head);
|
|
serverSocket.pipe(clientSocket);
|
|
clientSocket.pipe(serverSocket);
|
|
});
|
|
|
|
serverSocket.on('error', (err) => {
|
|
console.error(`[PROXY] Error connecting to destination: ${err.message}`);
|
|
clientSocket.end(`HTTP/1.1 502 Bad Gateway\r\n\r\n`);
|
|
});
|
|
} else {
|
|
console.log(`[PROXY] Denying connection to ${hostname}:${port}`);
|
|
clientSocket.end('HTTP/1.1 403 Forbidden\r\n\r\n');
|
|
}
|
|
|
|
clientSocket.on('error', (err) => {
|
|
// This can happen if the client hangs up.
|
|
console.error(`[PROXY] Client socket error: ${err.message}`);
|
|
});
|
|
});
|
|
|
|
server.listen(PROXY_PORT, () => {
|
|
const address = server.address();
|
|
console.log(`[PROXY] Proxy listening on ${address.address}:${address.port}`);
|
|
console.log(
|
|
`[PROXY] Allowing HTTPS connections to domains: ${ALLOWED_DOMAINS.join(', ')}`,
|
|
);
|
|
});
|