wormhole-proxy 3.3.2__tar.gz → 3.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/PKG-INFO +1 -1
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/pyproject.toml +1 -1
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/handler.py +11 -3
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/proxy.py +25 -5
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/resolver.py +8 -5
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/safeguards.py +26 -6
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/LICENSE +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/README.md +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/__init__.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/__main__.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/ad_blocker.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/auth_manager.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/authentication.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/logger.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/server.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/tools.py +0 -0
- {wormhole_proxy-3.3.2 → wormhole_proxy-3.3.4}/wormhole/version.py +0 -0
|
@@ -303,9 +303,13 @@ async def process_https_tunnel(
|
|
|
303
303
|
|
|
304
304
|
finally:
|
|
305
305
|
# Ensure server streams are closed if they were opened.
|
|
306
|
-
if server_writer and not server_writer.is_closing():
|
|
306
|
+
if server_writer is not None and not server_writer.is_closing():
|
|
307
307
|
server_writer.close()
|
|
308
|
-
|
|
308
|
+
wc = getattr(server_writer, "wait_closed", None)
|
|
309
|
+
if callable(wc):
|
|
310
|
+
result = wc()
|
|
311
|
+
if asyncio.iscoroutine(result):
|
|
312
|
+
await result
|
|
309
313
|
|
|
310
314
|
|
|
311
315
|
async def _send_http_request(
|
|
@@ -432,7 +436,11 @@ async def process_http_request(
|
|
|
432
436
|
)
|
|
433
437
|
if server_writer and not server_writer.is_closing():
|
|
434
438
|
server_writer.close()
|
|
435
|
-
|
|
439
|
+
wc = getattr(server_writer, "wait_closed", None)
|
|
440
|
+
if callable(wc):
|
|
441
|
+
result = wc()
|
|
442
|
+
if asyncio.iscoroutine(result):
|
|
443
|
+
await result
|
|
436
444
|
|
|
437
445
|
# Attempt 2: Fallback to original HTTP/1.0
|
|
438
446
|
original_headers = [
|
|
@@ -49,8 +49,16 @@ async def main_async(args) -> None:
|
|
|
49
49
|
)
|
|
50
50
|
)
|
|
51
51
|
|
|
52
|
+
# Initialize the resolver with the configured verbosity.
|
|
53
|
+
resolver.initialize(verbose=args.verbose)
|
|
54
|
+
|
|
52
55
|
if args.allowlist:
|
|
53
|
-
num_allowed = load_allowlist(
|
|
56
|
+
num_allowed = load_allowlist(
|
|
57
|
+
args.allowlist,
|
|
58
|
+
args.host,
|
|
59
|
+
ident={"id": "000000", "client": args.host},
|
|
60
|
+
verbose=args.verbose,
|
|
61
|
+
)
|
|
54
62
|
if num_allowed > 0:
|
|
55
63
|
logger.info(
|
|
56
64
|
flm(
|
|
@@ -61,7 +69,12 @@ async def main_async(args) -> None:
|
|
|
61
69
|
)
|
|
62
70
|
|
|
63
71
|
if args.ad_block_db:
|
|
64
|
-
num_blocked = await load_ad_block_db(
|
|
72
|
+
num_blocked = await load_ad_block_db(
|
|
73
|
+
args.ad_block_db,
|
|
74
|
+
args.host,
|
|
75
|
+
ident={"id": "000000", "client": args.host},
|
|
76
|
+
verbose=args.verbose,
|
|
77
|
+
)
|
|
65
78
|
if num_blocked > 0:
|
|
66
79
|
logger.info(
|
|
67
80
|
flm(
|
|
@@ -73,11 +86,18 @@ async def main_async(args) -> None:
|
|
|
73
86
|
|
|
74
87
|
shutdown_event = asyncio.Event()
|
|
75
88
|
|
|
89
|
+
def _shutdown_handler():
|
|
90
|
+
"""Handles shutdown signals to gracefully stop the server."""
|
|
91
|
+
shutdown_event.set()
|
|
92
|
+
|
|
76
93
|
# Set up signal handlers for graceful shutdown.
|
|
77
94
|
loop = asyncio.get_running_loop()
|
|
78
|
-
|
|
79
|
-
loop.add_signal_handler(sig,
|
|
95
|
+
[
|
|
96
|
+
loop.add_signal_handler(sig, _shutdown_handler)
|
|
97
|
+
for sig in (signal.SIGINT, signal.SIGTERM)
|
|
98
|
+
]
|
|
80
99
|
|
|
100
|
+
# Start the Wormhole server with the provided arguments.
|
|
81
101
|
server = await start_wormhole_server(
|
|
82
102
|
args.host,
|
|
83
103
|
args.port,
|
|
@@ -86,6 +106,7 @@ async def main_async(args) -> None:
|
|
|
86
106
|
args.allow_private,
|
|
87
107
|
)
|
|
88
108
|
|
|
109
|
+
# Log the server startup completion, 000000 means internal server ID.
|
|
89
110
|
logger.info(
|
|
90
111
|
flm(
|
|
91
112
|
"Server startup complete. Waiting for connections...",
|
|
@@ -246,7 +267,6 @@ def main() -> int:
|
|
|
246
267
|
args.verbose,
|
|
247
268
|
async_mode=is_server_mode,
|
|
248
269
|
)
|
|
249
|
-
resolver.configure(verbose=args.verbose)
|
|
250
270
|
|
|
251
271
|
if args.update_ad_block_db:
|
|
252
272
|
# For this standalone utility, configure a simple logger to show progress.
|
|
@@ -32,12 +32,12 @@ class Resolver:
|
|
|
32
32
|
self.resolver: aiodns.DNSResolver | None = None
|
|
33
33
|
self.hosts_cache: dict[str, str] = {}
|
|
34
34
|
self.verbose: int = 0 # Verbosity level, configured separately
|
|
35
|
-
self._load_hosts_file()
|
|
36
35
|
Resolver._instance = self
|
|
37
36
|
|
|
38
|
-
def
|
|
39
|
-
"""
|
|
37
|
+
def initialize(self, verbose: int) -> None:
|
|
38
|
+
"""Initializes the resolver with a verbosity level and loads the hosts file."""
|
|
40
39
|
self.verbose = verbose
|
|
40
|
+
self._load_hosts_file()
|
|
41
41
|
|
|
42
42
|
@staticmethod
|
|
43
43
|
def get_instance() -> "Resolver":
|
|
@@ -64,7 +64,7 @@ class Resolver:
|
|
|
64
64
|
def _load_hosts_file(self) -> None:
|
|
65
65
|
"""Parses the system's hosts file and populates the cache."""
|
|
66
66
|
hosts_path = self._get_hosts_path()
|
|
67
|
-
ident = {"id": "
|
|
67
|
+
ident = {"id": "000000", "client": "0.0.0.0"}
|
|
68
68
|
|
|
69
69
|
if not hosts_path.exists():
|
|
70
70
|
logger.warning(
|
|
@@ -144,7 +144,10 @@ class Resolver:
|
|
|
144
144
|
for res in results:
|
|
145
145
|
if isinstance(res, list):
|
|
146
146
|
for record in res:
|
|
147
|
-
|
|
147
|
+
if isinstance(record.host, bytes):
|
|
148
|
+
resolved_ips.add(record.host.decode())
|
|
149
|
+
else:
|
|
150
|
+
resolved_ips.add(record.host)
|
|
148
151
|
elif isinstance(res, aiodns.error.DNSError):
|
|
149
152
|
# Ignore common "not found" errors. Log other DNS errors for debugging.
|
|
150
153
|
if res.args[0] not in (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .logger import logger
|
|
1
|
+
from .logger import logger, format_log_message as flm
|
|
2
2
|
from functools import lru_cache
|
|
3
3
|
import aiosqlite
|
|
4
4
|
import ipaddress
|
|
@@ -7,6 +7,8 @@ import sys
|
|
|
7
7
|
|
|
8
8
|
# A hardcoded default allowlist for most known safe domains.
|
|
9
9
|
DEFAULT_ALLOWLIST: set[str] = {
|
|
10
|
+
"bit.ly", # Bitly for URL shortening
|
|
11
|
+
"azurewebsites.net", # Azure Web App
|
|
10
12
|
"s3.amazonaws.com", # Amazon S3 for static assets"
|
|
11
13
|
"fonts.googleapis.com", # Google Fonts
|
|
12
14
|
"safebrowsing.googleapis.com", # Google Safe Browsing for security
|
|
@@ -84,7 +86,9 @@ def is_private_ip(ip_str: str) -> bool:
|
|
|
84
86
|
return True
|
|
85
87
|
|
|
86
88
|
|
|
87
|
-
async def load_ad_block_db(
|
|
89
|
+
async def load_ad_block_db(
|
|
90
|
+
path: str, host: str, ident: dict[str, str], verbose: int = 0
|
|
91
|
+
) -> int:
|
|
88
92
|
"""
|
|
89
93
|
Loads a list of domains to block from a SQLite database into a global set
|
|
90
94
|
for fast in-memory access.
|
|
@@ -105,7 +109,11 @@ async def load_ad_block_db(path: str, host: str) -> int:
|
|
|
105
109
|
AD_BLOCK_SET.add(row[0])
|
|
106
110
|
except Exception as e:
|
|
107
111
|
logger.error(
|
|
108
|
-
|
|
112
|
+
flm(
|
|
113
|
+
f"Could not load ad-block database from '{path}': {e}",
|
|
114
|
+
ident=ident,
|
|
115
|
+
verbose=verbose,
|
|
116
|
+
)
|
|
109
117
|
)
|
|
110
118
|
|
|
111
119
|
if AD_BLOCK_SET:
|
|
@@ -114,13 +122,19 @@ async def load_ad_block_db(path: str, host: str) -> int:
|
|
|
114
122
|
content_size = sum(sys.getsizeof(s) for s in AD_BLOCK_SET)
|
|
115
123
|
total_size_mb = (set_size + content_size) / (1024 * 1024)
|
|
116
124
|
logger.debug(
|
|
117
|
-
|
|
125
|
+
flm(
|
|
126
|
+
f"Ad-block set memory usage: ~{total_size_mb:.2f} MB for {len(AD_BLOCK_SET)} domains",
|
|
127
|
+
ident=ident,
|
|
128
|
+
verbose=verbose,
|
|
129
|
+
)
|
|
118
130
|
)
|
|
119
131
|
|
|
120
132
|
return len(AD_BLOCK_SET)
|
|
121
133
|
|
|
122
134
|
|
|
123
|
-
def load_allowlist(
|
|
135
|
+
def load_allowlist(
|
|
136
|
+
path: str, host: str, ident: dict[str, str], verbose: int = 0
|
|
137
|
+
) -> int:
|
|
124
138
|
"""
|
|
125
139
|
Loads domains from a user-provided file and adds them to the global allowlist set.
|
|
126
140
|
"""
|
|
@@ -130,7 +144,13 @@ def load_allowlist(path: str, host: str) -> int:
|
|
|
130
144
|
if line.strip() and not line.startswith("#"):
|
|
131
145
|
ALLOW_LIST_SET.add(line.strip().lower())
|
|
132
146
|
except FileNotFoundError:
|
|
133
|
-
logger.error(
|
|
147
|
+
logger.error(
|
|
148
|
+
flm(
|
|
149
|
+
f"Allowlist file not found at '{path}'",
|
|
150
|
+
ident=ident,
|
|
151
|
+
verbose=verbose,
|
|
152
|
+
)
|
|
153
|
+
)
|
|
134
154
|
return len(ALLOW_LIST_SET)
|
|
135
155
|
|
|
136
156
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|