somratpro commited on
Commit
2f78318
·
1 Parent(s): 8c8a0c5

fix: explicit servername (SNI) for outbound proxy TLS stability

Browse files
Files changed (1) hide show
  1. outbound-fix.js +43 -28
outbound-fix.js CHANGED
@@ -3,8 +3,6 @@
3
  *
4
  * Patches https.request to redirect traffic for Telegram/Discord
5
  * through a Cloudflare Worker proxy.
6
- *
7
- * Set OUTBOUND_PROXY_URL to your Cloudflare Worker URL.
8
  */
9
  "use strict";
10
 
@@ -15,7 +13,14 @@ let PROXY_URL = process.env.OUTBOUND_PROXY_URL;
15
  if (PROXY_URL && !PROXY_URL.startsWith("http://") && !PROXY_URL.startsWith("https://")) {
16
  PROXY_URL = `https://${PROXY_URL}`;
17
  }
18
- const BLOCKED_DOMAINS = ["api.telegram.org", "discord.com", "gateway.discord.gg"];
 
 
 
 
 
 
 
19
 
20
  if (PROXY_URL) {
21
  try {
@@ -23,11 +28,13 @@ if (PROXY_URL) {
23
  const originalHttpsRequest = https.request;
24
  const originalHttpRequest = http.request;
25
 
26
- const patch = (original) => {
27
  return function (options, callback) {
28
  let hostname = "";
29
  let path = "";
 
30
 
 
31
  if (typeof options === "string") {
32
  const u = new URL(options);
33
  hostname = u.hostname;
@@ -35,36 +42,45 @@ if (PROXY_URL) {
35
  } else if (options instanceof URL) {
36
  hostname = options.hostname;
37
  path = options.pathname + options.search;
 
38
  } else {
39
  hostname = options.hostname || (options.host ? options.host.split(":")[0] : "");
40
  path = options.path || "/";
 
41
  }
42
 
43
- if (BLOCKED_DOMAINS.includes(hostname) && !options._proxied) {
 
 
 
 
44
  console.log(`[outbound-fix] Redirecting ${hostname}${path} -> ${proxy.hostname}`);
45
 
46
- // Create new options
47
- const newOptions = typeof options === "string" || options instanceof URL
48
- ? new URL(options.toString())
49
  : { ...options };
50
 
51
- // Mark to prevent recursion
52
- if (typeof newOptions === "object") {
53
- newOptions._proxied = true;
54
-
55
- // Set headers
56
- newOptions.headers = {
57
- ...(newOptions.headers || {}),
58
- host: proxy.host,
59
- "x-target-host": hostname // Tell the worker where to go
60
- };
61
-
62
- newOptions.hostname = proxy.hostname;
63
- newOptions.host = proxy.host;
64
- newOptions.port = proxy.port || 443;
65
- }
66
-
67
- // Force HTTPS if it was HTTP (unlikely for these domains but good for safety)
 
 
 
68
  return originalHttpsRequest.call(https, newOptions, callback);
69
  }
70
 
@@ -72,9 +88,8 @@ if (PROXY_URL) {
72
  };
73
  };
74
 
75
- https.request = patch(originalHttpsRequest);
76
- // Also patch http.request in case someone tries to use plain HTTP for these
77
- http.request = patch(originalHttpRequest);
78
 
79
  console.log(`[outbound-fix] Transparent proxy active for: ${BLOCKED_DOMAINS.join(", ")}`);
80
  console.log(`[outbound-fix] Target proxy: ${proxy.hostname}`);
 
3
  *
4
  * Patches https.request to redirect traffic for Telegram/Discord
5
  * through a Cloudflare Worker proxy.
 
 
6
  */
7
  "use strict";
8
 
 
13
  if (PROXY_URL && !PROXY_URL.startsWith("http://") && !PROXY_URL.startsWith("https://")) {
14
  PROXY_URL = `https://${PROXY_URL}`;
15
  }
16
+
17
+ const BLOCKED_DOMAINS = [
18
+ "api.telegram.org",
19
+ "discord.com",
20
+ "discordapp.com",
21
+ "gateway.discord.gg",
22
+ "status.discord.com"
23
+ ];
24
 
25
  if (PROXY_URL) {
26
  try {
 
28
  const originalHttpsRequest = https.request;
29
  const originalHttpRequest = http.request;
30
 
31
+ const patch = (original, isHttps) => {
32
  return function (options, callback) {
33
  let hostname = "";
34
  let path = "";
35
+ let headers = {};
36
 
37
+ // 1. Extract hostname and path from various possible input types
38
  if (typeof options === "string") {
39
  const u = new URL(options);
40
  hostname = u.hostname;
 
42
  } else if (options instanceof URL) {
43
  hostname = options.hostname;
44
  path = options.pathname + options.search;
45
+ headers = options.headers || {};
46
  } else {
47
  hostname = options.hostname || (options.host ? options.host.split(":")[0] : "");
48
  path = options.path || "/";
49
+ headers = options.headers || {};
50
  }
51
 
52
+ // 2. Check if we should intercept (and prevent recursion)
53
+ const isBlocked = BLOCKED_DOMAINS.some(domain => hostname === domain || hostname.endsWith("." + domain));
54
+ const alreadyProxied = options._proxied || (headers && headers["x-target-host"]);
55
+
56
+ if (isBlocked && !alreadyProxied) {
57
  console.log(`[outbound-fix] Redirecting ${hostname}${path} -> ${proxy.hostname}`);
58
 
59
+ // 3. Create fresh options for the proxied request
60
+ const newOptions = (typeof options === "string" || options instanceof URL)
61
+ ? { protocol: "https:", path: path }
62
  : { ...options };
63
 
64
+ // Ensure it's an object we can modify
65
+ if (typeof newOptions !== "object") return original.apply(this, arguments);
66
+
67
+ newOptions._proxied = true;
68
+ newOptions.protocol = "https:";
69
+ newOptions.hostname = proxy.hostname;
70
+ newOptions.host = proxy.host;
71
+ newOptions.port = proxy.port || 443;
72
+
73
+ // CRITICAL: Set servername for correct TLS/SNI handshake with Cloudflare
74
+ newOptions.servername = proxy.hostname;
75
+
76
+ // Merge and update headers
77
+ newOptions.headers = {
78
+ ...(headers || {}),
79
+ "host": proxy.host,
80
+ "x-target-host": hostname
81
+ };
82
+
83
+ // Always use HTTPS for the proxy connection
84
  return originalHttpsRequest.call(https, newOptions, callback);
85
  }
86
 
 
88
  };
89
  };
90
 
91
+ https.request = patch(originalHttpsRequest, true);
92
+ http.request = patch(originalHttpRequest, false);
 
93
 
94
  console.log(`[outbound-fix] Transparent proxy active for: ${BLOCKED_DOMAINS.join(", ")}`);
95
  console.log(`[outbound-fix] Target proxy: ${proxy.hostname}`);