wormhole-proxy 3.4.0__tar.gz → 3.4.2__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.4.0 → wormhole_proxy-3.4.2}/PKG-INFO +1 -1
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/pyproject.toml +2 -2
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/handler.py +11 -9
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/logger.py +7 -2
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/proxy.py +23 -6
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/resolver.py +35 -6
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/LICENSE +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/README.md +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/__init__.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/__main__.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/ad_blocker.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/auth_manager.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/authentication.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/context.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/safeguards.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/server.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/tools.py +0 -0
- {wormhole_proxy-3.4.0 → wormhole_proxy-3.4.2}/wormhole/version.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Main project metadata (PEP 621 standard)
|
|
2
2
|
[project]
|
|
3
3
|
name = "wormhole-proxy"
|
|
4
|
-
version = "3.4.
|
|
4
|
+
version = "3.4.2"
|
|
5
5
|
description = "Asynchronous I/O HTTP and HTTPS Proxy on Python >= 3.11"
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
authors = [
|
|
@@ -77,4 +77,4 @@ filterwarnings = [
|
|
|
77
77
|
# Build system configuration
|
|
78
78
|
[build-system]
|
|
79
79
|
requires = ["poetry-core>=1.0.0"]
|
|
80
|
-
build-backend = "poetry.core.masonry.api"
|
|
80
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -9,8 +9,9 @@ import random
|
|
|
9
9
|
import time
|
|
10
10
|
|
|
11
11
|
# --- DNS Cache for Performance ---
|
|
12
|
-
DNS_CACHE: dict[str, tuple[list[str], float]] =
|
|
13
|
-
|
|
12
|
+
DNS_CACHE: dict[str, tuple[list[str], float, float]] = (
|
|
13
|
+
{}
|
|
14
|
+
) # (ip_list, timestamp, ttl_expiration)
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
# --- Modernized Relay Stream Function ---
|
|
@@ -96,8 +97,8 @@ async def _resolve_and_validate_host(
|
|
|
96
97
|
|
|
97
98
|
# Check cache first
|
|
98
99
|
if host in DNS_CACHE:
|
|
99
|
-
ip_list, timestamp = DNS_CACHE[host]
|
|
100
|
-
if time.time()
|
|
100
|
+
ip_list, timestamp, ttl_expiration = DNS_CACHE[host]
|
|
101
|
+
if time.time() < ttl_expiration:
|
|
101
102
|
logger.debug(
|
|
102
103
|
flm(
|
|
103
104
|
f"DNS cache hit for '{host}'. ({len(DNS_CACHE)} hosts cached)",
|
|
@@ -107,9 +108,9 @@ async def _resolve_and_validate_host(
|
|
|
107
108
|
)
|
|
108
109
|
return ip_list
|
|
109
110
|
|
|
110
|
-
# Resolve hostname using aiodns resolver
|
|
111
|
+
# Resolve hostname using aiodns resolver with TTL information
|
|
111
112
|
try:
|
|
112
|
-
resolved_ips = await resolver.
|
|
113
|
+
resolved_ips, min_ttl = await resolver.resolve_with_ttl(host)
|
|
113
114
|
except OSError as e:
|
|
114
115
|
raise OSError(f"Failed to resolve host: {host}") from e
|
|
115
116
|
|
|
@@ -154,13 +155,14 @@ async def _resolve_and_validate_host(
|
|
|
154
155
|
f"Blocked access to '{host}' as it resolved to only private/reserved IPs."
|
|
155
156
|
)
|
|
156
157
|
|
|
157
|
-
# Update cache
|
|
158
|
-
|
|
158
|
+
# Update cache with TTL-based expiration
|
|
159
|
+
ttl_expiration = time.time() + min_ttl
|
|
160
|
+
DNS_CACHE[host] = (final_ip_list, time.time(), ttl_expiration)
|
|
159
161
|
logger.debug(
|
|
160
162
|
flm(
|
|
161
163
|
(
|
|
162
164
|
f"DNS cache miss for '{host}'. "
|
|
163
|
-
f"Resolved to {final_ip_list}. Caching. "
|
|
165
|
+
f"Resolved to {final_ip_list} with TTL {min_ttl}s. Caching until {ttl_expiration}. "
|
|
164
166
|
f"({len(DNS_CACHE)} hosts cached)"
|
|
165
167
|
),
|
|
166
168
|
context.ident,
|
|
@@ -82,8 +82,13 @@ class LogThrottler:
|
|
|
82
82
|
if self.timer:
|
|
83
83
|
self.timer.cancel()
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
try:
|
|
86
|
+
loop = asyncio.get_running_loop()
|
|
87
|
+
self.timer = loop.call_later(self.delay, self._flush_summary)
|
|
88
|
+
except RuntimeError:
|
|
89
|
+
# If there's no running event loop, log the message directly
|
|
90
|
+
# This can happen in synchronous test cases
|
|
91
|
+
self._flush_summary()
|
|
87
92
|
|
|
88
93
|
|
|
89
94
|
# In loguru, the logger is imported and ready to be configured.
|
|
@@ -281,8 +281,13 @@ def main() -> int:
|
|
|
281
281
|
# Determine if we are running the full async server or a utility.
|
|
282
282
|
is_server_mode = not args.update_ad_block_db
|
|
283
283
|
|
|
284
|
-
#
|
|
285
|
-
if uvloop
|
|
284
|
+
# Use the new uvloop.run() approach for Python 3.12+
|
|
285
|
+
# For older versions or if uvloop is not available, we'll use the standard approach
|
|
286
|
+
if uvloop and hasattr(uvloop, "run"):
|
|
287
|
+
# For Python 3.12+, we'll use uvloop.run() directly when starting the server
|
|
288
|
+
pass # We'll handle this in the asyncio.run() call
|
|
289
|
+
elif uvloop:
|
|
290
|
+
# For older versions, use the deprecated install() method
|
|
286
291
|
uvloop.install()
|
|
287
292
|
|
|
288
293
|
# Setup logging. Disable async features for synchronous utility commands.
|
|
@@ -297,9 +302,16 @@ def main() -> int:
|
|
|
297
302
|
# For this standalone utility, configure a simple logger to show progress.
|
|
298
303
|
logger.info(f"Updating ad-block database at: {args.update_ad_block_db}")
|
|
299
304
|
try:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
305
|
+
if uvloop and hasattr(uvloop, "run"):
|
|
306
|
+
# Use the new uvloop.run() method for Python 3.12+
|
|
307
|
+
uvloop.run(
|
|
308
|
+
update_database(args.update_ad_block_db, args.allowlist)
|
|
309
|
+
)
|
|
310
|
+
else:
|
|
311
|
+
# Use the standard asyncio.run() for older versions or if uvloop is not available
|
|
312
|
+
asyncio.run(
|
|
313
|
+
update_database(args.update_ad_block_db, args.allowlist)
|
|
314
|
+
)
|
|
303
315
|
except Exception as e:
|
|
304
316
|
logger.error(f"\nAn error occurred during update: {e}")
|
|
305
317
|
return 1
|
|
@@ -313,7 +325,12 @@ def main() -> int:
|
|
|
313
325
|
parser.error(f"Authentication file not found: {args.auth}")
|
|
314
326
|
|
|
315
327
|
try:
|
|
316
|
-
|
|
328
|
+
if uvloop and hasattr(uvloop, "run"):
|
|
329
|
+
# Use the new uvloop.run() method for Python 3.12+
|
|
330
|
+
uvloop.run(main_async(args))
|
|
331
|
+
else:
|
|
332
|
+
# Use the standard asyncio.run() for older versions or if uvloop is not available
|
|
333
|
+
asyncio.run(main_async(args))
|
|
317
334
|
except KeyboardInterrupt:
|
|
318
335
|
print("\nInterrupted by user. Exiting.")
|
|
319
336
|
except Exception as e:
|
|
@@ -137,18 +137,18 @@ class Resolver:
|
|
|
137
137
|
)
|
|
138
138
|
)
|
|
139
139
|
|
|
140
|
-
async def
|
|
140
|
+
async def resolve_with_ttl(self, hostname: str) -> tuple[list[str], int]:
|
|
141
141
|
"""
|
|
142
|
-
Resolves a hostname to a list of IP addresses.
|
|
142
|
+
Resolves a hostname to a list of IP addresses and the minimum TTL.
|
|
143
143
|
|
|
144
144
|
1. Checks the local hosts file cache first.
|
|
145
|
-
2. If not found, queries DNS for A and AAAA records using aiodns.
|
|
145
|
+
2. If not found, queries DNS for A and AAAA records using aiodns and extracts TTL.
|
|
146
146
|
|
|
147
147
|
Args:
|
|
148
148
|
hostname (str): The hostname to resolve.
|
|
149
149
|
|
|
150
150
|
Returns:
|
|
151
|
-
list[str]: A list of IP addresses
|
|
151
|
+
tuple[list[str], int]: A list of IP addresses and the minimum TTL value.
|
|
152
152
|
|
|
153
153
|
Raises:
|
|
154
154
|
OSError: If no IP addresses could be resolved.
|
|
@@ -171,7 +171,8 @@ class Resolver:
|
|
|
171
171
|
self.verbose,
|
|
172
172
|
)
|
|
173
173
|
)
|
|
174
|
-
|
|
174
|
+
# Hosts file entries don't have TTL, use a default high value
|
|
175
|
+
return [ip], 3600
|
|
175
176
|
|
|
176
177
|
# 2. Query DNS using aiodns for IPv4 and IPv6 addresses concurrently
|
|
177
178
|
results = await asyncio.gather(
|
|
@@ -181,6 +182,8 @@ class Resolver:
|
|
|
181
182
|
)
|
|
182
183
|
|
|
183
184
|
resolved_ips: set[str] = set()
|
|
185
|
+
min_ttl = float("inf")
|
|
186
|
+
|
|
184
187
|
for res in results:
|
|
185
188
|
if isinstance(res, list):
|
|
186
189
|
for record in res:
|
|
@@ -188,6 +191,9 @@ class Resolver:
|
|
|
188
191
|
resolved_ips.add(record.host.decode())
|
|
189
192
|
else:
|
|
190
193
|
resolved_ips.add(record.host)
|
|
194
|
+
# Extract TTL from record
|
|
195
|
+
if hasattr(record, "ttl") and record.ttl < min_ttl:
|
|
196
|
+
min_ttl = record.ttl
|
|
191
197
|
elif isinstance(res, aiodns.error.DNSError):
|
|
192
198
|
# Ignore common "not found" errors. Log other DNS errors for debugging.
|
|
193
199
|
if res.args[0] not in (
|
|
@@ -209,7 +215,30 @@ class Resolver:
|
|
|
209
215
|
if not resolved_ips:
|
|
210
216
|
raise OSError(f"Failed to resolve host: {hostname}")
|
|
211
217
|
|
|
212
|
-
|
|
218
|
+
# If no TTL was found (shouldn't happen but just in case), use default
|
|
219
|
+
if min_ttl == float("inf"):
|
|
220
|
+
min_ttl = 300
|
|
221
|
+
|
|
222
|
+
return list(resolved_ips), int(min_ttl)
|
|
223
|
+
|
|
224
|
+
async def resolve(self, hostname: str) -> list[str]:
|
|
225
|
+
"""
|
|
226
|
+
Resolves a hostname to a list of IP addresses.
|
|
227
|
+
|
|
228
|
+
1. Checks the local hosts file cache first.
|
|
229
|
+
2. If not found, queries DNS for A and AAAA records using aiodns.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
hostname (str): The hostname to resolve.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
list[str]: A list of IP addresses associated with the hostname.
|
|
236
|
+
|
|
237
|
+
Raises:
|
|
238
|
+
OSError: If no IP addresses could be resolved.
|
|
239
|
+
"""
|
|
240
|
+
ips, _ = await self.resolve_with_ttl(hostname)
|
|
241
|
+
return ips
|
|
213
242
|
|
|
214
243
|
|
|
215
244
|
# Initialize the singleton instance so it's ready for other modules to import
|
|
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
|
|
File without changes
|