Skip to content

Commit 840e554

Browse files
committed
7.30 auto-commit
1 parent 6a4a26c commit 840e554

File tree

5 files changed

+119
-17
lines changed

5 files changed

+119
-17
lines changed

CHANGELOG.txt

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
7.30
2+
* 修复雷电/夜神兼容性问题
3+
* 一些小调整
4+
15
7.28
26
* 新增 show_toast 接口
37
* 内置代理现已支持代理 DNS 流量

lamda/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
#
33
# Distributed under MIT license.
44
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5-
__version__ = "7.28"
5+
__version__ = "7.30"

lamda/client.py

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"OpenVPNAuth",
7373
"OpenVPNEncryption",
7474
"OpenVPNKeyDirection",
75+
"ToastDuration",
7576
"OpenVPNCipher",
7677
"OpenVPNProto",
7778
"Orientation",

tools/requirements.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
mitmproxy>=7.0.0,<10.0.0
1+
mitmproxy>=9.0.0,<=10.2.0
2+
dnspython
3+
httpx[socks]
24
packaging

tools/startmitm.py

+110-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
#!/usr/bin/env python3
2+
# Copyright 2024 rev1si0n ([email protected]). All rights reserved.
3+
#
4+
# Distributed under MIT license.
5+
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
26
#encoding=utf-8
37
import os
8+
import re
49
import sys
510
import time
11+
import logging
612
import subprocess
713
import argparse
814
import uuid
15+
import asyncio
16+
import threading
17+
import dns.message
18+
import dns.query
19+
import httpx
920

1021
from socket import *
1122
from random import randint
1223
from multiprocessing import Process
24+
from urllib.parse import urlparse
25+
from functools import partial
1326

1427
from mitmproxy.certs import CertStore
1528
from mitmproxy.tools.main import mitmweb as web
@@ -36,15 +49,87 @@ def cleanup(*args, **kwargs):
3649
os._exit (0)
3750

3851

52+
def is_doh(server):
53+
u = urlparse(server)
54+
return u.scheme in ("http", "https")
55+
56+
57+
def fmt_rdns(dns, lport):
58+
return "reverse:dns://{}@{}".format(dns, lport)
59+
60+
61+
class DOHProxiedProtocol(asyncio.Protocol):
62+
def __init__(self, loop, server, proxy):
63+
self.server = server
64+
log ("using DOH: {}".format(server))
65+
self.client = httpx.Client(proxies=proxy)
66+
self.loop = loop
67+
def datagram_received(self, pkt, addr):
68+
self.loop.create_task(self.handle(pkt, addr))
69+
def connection_made(self, transport):
70+
self.transport = transport
71+
async def handle(self, pkt, addr):
72+
res = await self.loop.run_in_executor(None,
73+
self.dns_query, pkt)
74+
self.transport.sendto(res, addr)
75+
def dns_query(self, pkt):
76+
res = dns.message.from_wire(pkt)
77+
res = dns.query.https(res, self.server,
78+
session=self.client)
79+
return res.to_wire()
80+
@classmethod
81+
def start(cls, *args, **kwargs):
82+
dns = threading.Thread(target=cls._start,
83+
args=args, kwargs=kwargs)
84+
dns.daemon = True
85+
dns.start()
86+
@classmethod
87+
def _start(cls, bind, port, upstream, proxy=None):
88+
loop = asyncio.new_event_loop()
89+
factory = partial(cls, loop, upstream, proxy)
90+
coro = loop.create_datagram_endpoint(factory,
91+
local_addr=(bind, port),
92+
reuse_port=True)
93+
loop.run_until_complete(coro)
94+
loop.run_forever()
95+
96+
97+
def setup_dns_upstream(args):
98+
port = randint(28080, 58080)
99+
dns = "{}:{}".format("127.0.0.1", port)
100+
DOHProxiedProtocol.start(
101+
"127.0.0.1",
102+
port,
103+
args.dns,
104+
args.upstream)
105+
args.dns = fmt_rdns(dns, proxy)
106+
107+
39108
def add_server(command, spec):
40109
spec and command.append("--mode")
41110
spec and command.append(spec)
42111

43112

113+
def add_upstream(args, ext):
114+
u = urlparse(args.upstream)
115+
upstream = "upstream:{}://{}:{}".format(u.scheme,
116+
u.hostname,
117+
u.port)
118+
args.mode = upstream
119+
cred = "{}:{}".format(u.username, u.password)
120+
u.username and ext.append("--upstream-auth")
121+
u.username and ext.append(cred)
122+
123+
44124
def log(*args):
45125
print (time.ctime(), *args)
46126

47127

128+
def die(*args):
129+
print (time.ctime(), *args)
130+
sys.exit (1)
131+
132+
48133
def adb(*args):
49134
command = ["adb"]
50135
if serial is not None:
@@ -103,15 +188,12 @@ def get_default_interface_ip(target):
103188
lamda = int(os.environ.get("PORT",
104189
65000))
105190

106-
def dnsopt(dns):
107-
return "reverse:dns://{}@{}".format(dns, proxy)
108191
argp.add_argument("device", nargs=1)
109-
argp.add_argument("-m", "--mode", default="regular")
192+
mod = argp.add_mutually_exclusive_group(required=False)
193+
mod.add_argument("-m", "--mode", default="regular")
194+
mod.add_argument("--upstream", type=str, default=None)
110195
argp.add_argument("--serial", type=str, default=None)
111-
dns = argp.add_mutually_exclusive_group(required=False)
112-
dns.add_argument("--dns", type=dnsopt, nargs="?",
113-
const="1.1.1.1")
114-
dns.add_argument("--nameserver", type=str, default="")
196+
argp.add_argument("--dns", type=str, default=None)
115197
args, extras = argp.parse_known_args()
116198
serial = args.serial
117199
host = args.device[0]
@@ -127,17 +209,30 @@ def dnsopt(dns):
127209

128210
if cert:
129211
log ("ssl:", cert)
212+
if args.upstream:
213+
add_upstream(args, extras)
130214
if usb and args.dns:
131-
log ("dns mitm not available over usb")
132-
sys.exit (1)
133-
if usb and (forward(lamda, lamda).wait() != 0 or \
134-
reverse(proxy, proxy).wait() != 0):
135-
log ("forward failed")
136-
sys.exit (1)
215+
die ("dns mitm not available in USB mode")
216+
if usb and args.upstream:
217+
log ("dns will not sent via upstream in USB mode")
218+
if args.upstream and not args.dns:
219+
die ("dns must be set in upstream mode")
220+
if args.upstream and args.dns and not is_doh(args.dns):
221+
die ("dns must be DOH in upstream mode")
222+
if usb and forward(lamda, lamda).wait() != 0:
223+
die ("adb forward failed")
224+
if usb and reverse(proxy, proxy).wait() != 0:
225+
die ("adb forward failed")
226+
if not args.upstream and args.dns and not is_doh(args.dns):
227+
args.dns = fmt_rdns(args.dns, proxy)
228+
if args.dns and is_doh(args.dns):
229+
setup_dns_upstream(args)
230+
137231

138232
# 创建设备实例
139233
d = Device(host, port=lamda,
140234
certificate=cert)
235+
logger.setLevel(logging.WARN)
141236

142237
# 拼接证书文件路径
143238
DIR = os.path.expanduser(CONF_DIR)
@@ -150,8 +245,8 @@ def dnsopt(dns):
150245
# 初始化 proxy 配置
151246
profile = GproxyProfile()
152247
profile.type = GproxyType.HTTP_CONNECT
153-
profile.nameserver = args.nameserver
154-
if not usb and args.dns:
248+
profile.nameserver = "1.1.1.1"
249+
if not usb and (args.upstream or args.dns):
155250
profile.nameserver = "{}:{}".format(server, proxy)
156251
profile.drop_udp = True
157252

0 commit comments

Comments
 (0)