procproxy 0.1.0__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.
- procproxy-0.1.0/LICENSE +21 -0
- procproxy-0.1.0/PKG-INFO +489 -0
- procproxy-0.1.0/README.md +450 -0
- procproxy-0.1.0/pyproject.toml +139 -0
- procproxy-0.1.0/setup.cfg +4 -0
- procproxy-0.1.0/src/procproxy.egg-info/PKG-INFO +489 -0
- procproxy-0.1.0/src/procproxy.egg-info/SOURCES.txt +48 -0
- procproxy-0.1.0/src/procproxy.egg-info/dependency_links.txt +1 -0
- procproxy-0.1.0/src/procproxy.egg-info/entry_points.txt +2 -0
- procproxy-0.1.0/src/procproxy.egg-info/requires.txt +15 -0
- procproxy-0.1.0/src/procproxy.egg-info/top_level.txt +1 -0
- procproxy-0.1.0/src/proxycore/__init__.py +7 -0
- procproxy-0.1.0/src/proxycore/__main__.py +65 -0
- procproxy-0.1.0/src/proxycore/api.py +226 -0
- procproxy-0.1.0/src/proxycore/backend/__init__.py +49 -0
- procproxy-0.1.0/src/proxycore/backend/base.py +159 -0
- procproxy-0.1.0/src/proxycore/backend/null.py +51 -0
- procproxy-0.1.0/src/proxycore/backend/windivert/__init__.py +657 -0
- procproxy-0.1.0/src/proxycore/backend/windivert/filter.py +123 -0
- procproxy-0.1.0/src/proxycore/backend/windivert/pidmap.py +289 -0
- procproxy-0.1.0/src/proxycore/backend/windivert/pkt.py +424 -0
- procproxy-0.1.0/src/proxycore/canproxy.py +229 -0
- procproxy-0.1.0/src/proxycore/checkroute.py +247 -0
- procproxy-0.1.0/src/proxycore/cli.py +605 -0
- procproxy-0.1.0/src/proxycore/config.py +1010 -0
- procproxy-0.1.0/src/proxycore/dns/__init__.py +46 -0
- procproxy-0.1.0/src/proxycore/dns/cache.py +209 -0
- procproxy-0.1.0/src/proxycore/dns/modes.py +451 -0
- procproxy-0.1.0/src/proxycore/dns/udp.py +606 -0
- procproxy-0.1.0/src/proxycore/forward.py +572 -0
- procproxy-0.1.0/src/proxycore/ipc.py +637 -0
- procproxy-0.1.0/src/proxycore/log.py +298 -0
- procproxy-0.1.0/src/proxycore/pathsetup.py +112 -0
- procproxy-0.1.0/src/proxycore/probe.py +168 -0
- procproxy-0.1.0/src/proxycore/proc.py +342 -0
- procproxy-0.1.0/src/proxycore/rules.py +730 -0
- procproxy-0.1.0/src/proxycore/runtime.py +654 -0
- procproxy-0.1.0/src/proxycore/service/__init__.py +536 -0
- procproxy-0.1.0/src/proxycore/service/__main__.py +124 -0
- procproxy-0.1.0/src/proxycore/tunnel/__init__.py +8 -0
- procproxy-0.1.0/src/proxycore/tunnel/relay.py +393 -0
- procproxy-0.1.0/src/proxycore/tunnel/sessions.py +315 -0
- procproxy-0.1.0/src/proxycore/tunnel/sink.py +325 -0
- procproxy-0.1.0/src/proxycore/types.py +165 -0
- procproxy-0.1.0/src/proxycore/upstream/__init__.py +52 -0
- procproxy-0.1.0/src/proxycore/upstream/base.py +150 -0
- procproxy-0.1.0/src/proxycore/upstream/chain.py +92 -0
- procproxy-0.1.0/src/proxycore/upstream/http_connect.py +148 -0
- procproxy-0.1.0/src/proxycore/upstream/socks4.py +106 -0
- procproxy-0.1.0/src/proxycore/upstream/socks5.py +266 -0
procproxy-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Longersking
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
procproxy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: procproxy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ProcProxy —— 进程级代理:按进程决定哪条连接走哪个上游代理
|
|
5
|
+
Author: Longersking
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Longersking/procproxy
|
|
8
|
+
Project-URL: Repository, https://github.com/Longersking/procproxy
|
|
9
|
+
Project-URL: Issues, https://github.com/Longersking/procproxy/issues
|
|
10
|
+
Keywords: proxy,transparent-proxy,process,windivert,windows,socks5
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Internet :: Proxy Servers
|
|
22
|
+
Classifier: Topic :: System :: Networking
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: PyYAML>=6.0
|
|
27
|
+
Provides-Extra: windivert
|
|
28
|
+
Requires-Dist: pydivert>=3.0; extra == "windivert"
|
|
29
|
+
Requires-Dist: psutil>=5.9; extra == "windivert"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=4.1; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
35
|
+
Provides-Extra: release
|
|
36
|
+
Requires-Dist: build>=1.2; extra == "release"
|
|
37
|
+
Requires-Dist: twine>=5; extra == "release"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# ProcProxy
|
|
41
|
+
|
|
42
|
+
**按「哪个进程」决定「哪条连接走哪个上游代理」** —— 对目标程序零侵入:
|
|
43
|
+
不注入 DLL、不改目标进程内存、不解密流量。
|
|
44
|
+
|
|
45
|
+
Windows · 基于 [WinDivert](https://github.com/basil00/WinDivert)(用户态 + 已签名的内核驱动)。
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 只有一个入口:`procproxy.py`
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python procproxy.py # ← 不知道从哪下手就跑这个:报环境状态 + 最常用的命令
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
它认识三种输入:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python procproxy.py # 无参数:环境状态 + 命令清单
|
|
59
|
+
python procproxy.py WeChat.exe --port 8848 # 进程名 → 把它的流量转发出去(主要用法)
|
|
60
|
+
python procproxy.py doctor | rules | sessions | ... # 子命令(等价于 python -m proxycore <子命令>)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
其余一切都在这三种之下,不需要你去找"该运行哪个文件"。
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 安装
|
|
68
|
+
|
|
69
|
+
需要 **Python 3.10+**。
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install -e .
|
|
73
|
+
# 或者不装(零依赖方式,往 site-packages 写一个 .pth,让 python -m proxycore 全局可用)
|
|
74
|
+
python procproxy.py install-path
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
数据面依赖(要用真抓包就必需):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install pydivert psutil
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> `pydivert` 自带**已签名**的 `WinDivert64.sys` —— 所以**不需要**开测试签名、不需要自己签驱动。
|
|
84
|
+
> 但**运行时需要管理员权限**(内核驱动只能由管理员加载)。
|
|
85
|
+
|
|
86
|
+
先自检一下:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python procproxy.py
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
ProcProxy —— 按进程选路的本机代理
|
|
94
|
+
====================================================================
|
|
95
|
+
|
|
96
|
+
配置文件 D:\tools\proxypy-public\samples\profiles\dev.yaml
|
|
97
|
+
OK(3 条规则 / 1 个上游)
|
|
98
|
+
数据面依赖 已安装(pydivert)
|
|
99
|
+
管理员权限 否 —— 真抓包改道需要管理员终端
|
|
100
|
+
...
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 让非管理员也能用(可选)
|
|
106
|
+
|
|
107
|
+
**默认不需要改**:不开这个功能时,IPC 命名管道只允许管理员 + SYSTEM,与以前完全一致。
|
|
108
|
+
|
|
109
|
+
**为什么需要它**:真拦截要开 WinDivert 设备,而那个设备只允许管理员打开
|
|
110
|
+
(实测:驱动已经是 `RUNNING`,非管理员仍然 `WinError 5` —— 卡的是设备的安全描述符,
|
|
111
|
+
不是"没装驱动")。所以**服务必须由管理员启动**,但"谁来用它"是可以放开的:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
管理员执行一次 普通用户之后可以
|
|
115
|
+
───────────────────────────── ────────────────────────────────
|
|
116
|
+
1. 建一个组(例如 ProcProxy Users)
|
|
117
|
+
2. 配置里写 service.ipc_allow_group
|
|
118
|
+
3. 装并以管理员启动服务 ───▶ python procproxy.py status / sessions / rules
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
配置:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
service:
|
|
125
|
+
ipc_allow_group: "ProcProxy Users" # 空 = 只有管理员(默认)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
然后在**管理员终端**:
|
|
129
|
+
|
|
130
|
+
```powershell
|
|
131
|
+
# 建组(一次性)
|
|
132
|
+
net localgroup "ProcProxy Users" /add
|
|
133
|
+
net localgroup "ProcProxy Users" alice /add
|
|
134
|
+
|
|
135
|
+
# 装服务(会先校验组名能不能解析,写错了当场报)
|
|
136
|
+
python -m proxycore.service install --config samples\profiles\dev.yaml
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
之后 `alice`(**不需要管理员**)就能:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
python procproxy.py status
|
|
143
|
+
python procproxy.py sessions --follow
|
|
144
|
+
python procproxy.py rules
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 权限边界(重要)
|
|
148
|
+
|
|
149
|
+
**被放行的组只能读,不能改**。这条不是靠 ACL,而是服务侧**按命令**判的:
|
|
150
|
+
|
|
151
|
+
| 命令 | 放行组 | 为什么 |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `status` / `sessions` / `rules` | ✅ 可读 | 只是看 |
|
|
154
|
+
| `reload`(换规则) | ❌ **需管理员令牌** | 能把**别人的**流量导到另一个上游 |
|
|
155
|
+
| `stop` / `panic` | ❌ **需管理员令牌** | 能让共享的服务停摆 |
|
|
156
|
+
|
|
157
|
+
原因:管道 ACL 只能**整体**授权 —— 要让人能发命令,就必须同时给他写权限。
|
|
158
|
+
所以"能不能改规则"表达不到 ACL 上,只能由服务侧再判一次(见 `ipc.ADMIN_ONLY_COMMANDS`)。
|
|
159
|
+
被放行的组拿到的也只是 `GRGW`(读+写),**不是 `GA`** —— `GA` 含 `WRITE_DAC`,
|
|
160
|
+
对方能反过来改管道自己的 ACL。
|
|
161
|
+
|
|
162
|
+
**仍然需要管理员的**:建组、装服务、启动服务。这三件事永远要有特权。
|
|
163
|
+
|
|
164
|
+
> ⚠️ **本机无法自测的部分**:跨用户"低权用户能连上管道"这条,需要一台装了服务 +
|
|
165
|
+
> 有第二个用户账户的机器才能验。本仓库只对**可离线验证的部分**做了断言
|
|
166
|
+
> (SDDL 拼装、按命令的权限判定、组名解析),其余如实标注、不伪装通过。
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 快速开始
|
|
171
|
+
|
|
172
|
+
### 1) 先看它真的能跑(不需要管理员)
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
python tests/tools/run_demo.py # 15 组自检案例
|
|
176
|
+
python tests/tools/run_e2e.py # 只跑端到端那条链路,约 2 秒
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`run_e2e.py` 会起 mock 上游 + mock 目标 + ProcProxy(`backend=null`),断言
|
|
180
|
+
"sink → 上游代理 → 目标"这条链路。**注意 `backend=null` 不抓包、不改道**。
|
|
181
|
+
|
|
182
|
+
### 2) 真正改道一个进程(需要管理员)
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
python procproxy.py curl.exe --port 7890
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
它会自动:① 探测那个端口是不是"代理监听";② 生成配置;③ 启动数据面。
|
|
189
|
+
加 `--check-only` 则只自检 + 生成配置 —— **不启动、不改任何流量、不需要管理员**:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
python procproxy.py curl.exe --port 7890 --check-only
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
另一个窗口验证(`--noproxy '*'` **必须加**,否则 curl 会走系统 `http_proxy`,测的就不是它了):
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
curl --noproxy '*' http://example.com/ -v
|
|
199
|
+
python procproxy.py sessions --follow
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 转发单个进程的流量到抓包工具(Yakit / Burp / Charles)
|
|
205
|
+
|
|
206
|
+
这是最常用的场景:**看某个程序到底发了什么**。
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# 第 1 步:自检(不动任何流量、不需要管理员)
|
|
210
|
+
python procproxy.py Weixin.exe --port 8848 --check-only
|
|
211
|
+
|
|
212
|
+
# 第 2 步:真跑(管理员终端)
|
|
213
|
+
python procproxy.py Weixin.exe --port 8848
|
|
214
|
+
|
|
215
|
+
# 第 3 步:操作那个程序(刷朋友圈、点开文章),然后 Ctrl+C
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
一次给多个进程名(也支持 `'a.exe;b.exe'` 或 `*` 通配符):
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
python procproxy.py Weixin.exe WeChatAppEx.exe --port 8848
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**怎么算成功(三层证据)**:
|
|
225
|
+
|
|
226
|
+
| # | 看哪里 | 成功的样子 |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| ① | ProcProxy 终端 | `session_end ... proc=Weixin.exe rule=r-watch upstream=capture` |
|
|
229
|
+
| ② | Yakit 的「MITM 交互式劫持」历史 | 出现对应的 `CONNECT 目标:端口` |
|
|
230
|
+
| ③ | 状态行 | `走代理 N 条` 随你的操作增长 |
|
|
231
|
+
|
|
232
|
+
⚠️ 只有 ① 没有 ② → 端口填错了(**要填抓包工具的 MITM 监听口,不是它的 Web 管理口**)。
|
|
233
|
+
① ② 都正常但内容看不懂 → 那是 TLS,不是转发的问题。
|
|
234
|
+
|
|
235
|
+
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](docs/14-把进程流量转发给抓包工具.md)。
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 子命令
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
python procproxy.py doctor # 环境自检
|
|
243
|
+
python procproxy.py rules # 打印规则表
|
|
244
|
+
python procproxy.py rules --trace --proc curl.exe --dst 1.1.1.1 --port 443
|
|
245
|
+
python procproxy.py config --json # 打印生效配置
|
|
246
|
+
python procproxy.py status # 运行时状态
|
|
247
|
+
python procproxy.py sessions --follow # 跟会话
|
|
248
|
+
python procproxy.py run # 前台跑数据面(需管理员)
|
|
249
|
+
python procproxy.py stop [--panic] # 停
|
|
250
|
+
|
|
251
|
+
# 下面这几个自带完整参数,用 --help 看:
|
|
252
|
+
python procproxy.py forward --help # 转发进程(上面的 <进程名> 就是它的简写)
|
|
253
|
+
python procproxy.py can-proxy --help # 一句话:现在能不能转发
|
|
254
|
+
python procproxy.py check-route --help # 核对某进程走了哪条路
|
|
255
|
+
python procproxy.py probe-upstream --help # 探测某端口是不是可用的上游代理
|
|
256
|
+
python procproxy.py install-path --help # 让 python -m proxycore 全局可用
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`--trace` 有个坑值得知道:`--pid` 默认是 `cli` 自己的 PID,所以 `G2 self-pid` 几乎永远是 `true`。
|
|
260
|
+
想看真实判定,显式传 `--pid <目标进程真实PID>`。
|
|
261
|
+
|
|
262
|
+
也可以完全不用 `procproxy.py`,直接 `python -m proxycore <同样的子命令>`。
|
|
263
|
+
|
|
264
|
+
### 当 Windows 服务
|
|
265
|
+
|
|
266
|
+
```powershell
|
|
267
|
+
python -m proxycore.service install --config samples\profiles\dev.yaml # 管理员
|
|
268
|
+
sc query procproxysvc
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 配置文件
|
|
274
|
+
|
|
275
|
+
```yaml
|
|
276
|
+
version: 1
|
|
277
|
+
|
|
278
|
+
service:
|
|
279
|
+
sink: { host: 127.0.0.1, port: 19080 } # 本地落地端口
|
|
280
|
+
backend: windivert # windivert | null
|
|
281
|
+
on_unknown_pid: direct # 查不到 PID 时:direct | proxy | block
|
|
282
|
+
on_decide_error: block # 决策抛异常时:默认 block(不放行)
|
|
283
|
+
loop_breaker: { window_s: 5, threshold: 50 }
|
|
284
|
+
|
|
285
|
+
profile:
|
|
286
|
+
name: dev
|
|
287
|
+
default_action: direct # 未命中任何规则时
|
|
288
|
+
sticky_per_pid: true # 同 PID 固定用同一个上游
|
|
289
|
+
dns_mode: remote # remote | local | bypass
|
|
290
|
+
|
|
291
|
+
upstreams:
|
|
292
|
+
- alias: local-mock
|
|
293
|
+
kind: socks5 # socks5 | socks4 | http | https
|
|
294
|
+
host: 127.0.0.1
|
|
295
|
+
port: 1080
|
|
296
|
+
# 口令不落明文:password_ref: "dpapi:alias" / "env:VAR" / "file:path"
|
|
297
|
+
# 多跳:chain: [hop-b, hop-c]
|
|
298
|
+
|
|
299
|
+
rules: # 自上而下,**首个命中生效**
|
|
300
|
+
- id: r1-private
|
|
301
|
+
action: direct
|
|
302
|
+
targets: "*"
|
|
303
|
+
dst_ip: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8"
|
|
304
|
+
- id: r2-curl
|
|
305
|
+
action: proxy
|
|
306
|
+
upstream: local-mock
|
|
307
|
+
targets: "curl.exe;curl"
|
|
308
|
+
- id: r3-default
|
|
309
|
+
action: direct
|
|
310
|
+
targets: "*"
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**规则匹配顺序**(顺序不可改,改了就变语义):
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
1. 未知 PID → 按 on_unknown_pid 兜底
|
|
317
|
+
2. 守卫 G1 → 回环/私网/链路本地 → DIRECT
|
|
318
|
+
3. 守卫 G2 → 自身进程 → DIRECT
|
|
319
|
+
4. 守卫 G3 → 上游 / 本地 DNS 端点 → DIRECT
|
|
320
|
+
5. 守卫 G4 → 同 (pid,dst) 熔断 → DIRECT + 告警
|
|
321
|
+
6. 规则表 → 自上而下,首个命中生效
|
|
322
|
+
7. 都没命中 → profile.default_action
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
完整语义见 [`docs/07-规则引擎与Profile格式.md`](docs/07-规则引擎与Profile格式.md)。
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## 编程接口
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
from proxycore import api
|
|
333
|
+
|
|
334
|
+
# 上下文管理器:退出自动停
|
|
335
|
+
with api.start_proxy("samples/profiles/dev.yaml") as handle:
|
|
336
|
+
print(handle.status())
|
|
337
|
+
|
|
338
|
+
# 测试模式:sink 把所有连接转发到固定目标(不做抓包)
|
|
339
|
+
with api.start_proxy("samples/profiles/dev.yaml", backend="null",
|
|
340
|
+
sink_test_target="127.0.0.1:8080") as handle:
|
|
341
|
+
...
|
|
342
|
+
|
|
343
|
+
# 只要规则决策,不要监听
|
|
344
|
+
runtime = api.make_runtime("samples/profiles/dev.yaml", backend="null")
|
|
345
|
+
decision = runtime.decide(conn_request)
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
跑 `python tests/tools/api_demo.py` 看三种用法的完整演示。
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## 工作原理(一页)
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
应用 connect()
|
|
356
|
+
│
|
|
357
|
+
▼
|
|
358
|
+
① Backend(WinDivert)把出向 TCP 包捞进用户态,并查表得出 PID
|
|
359
|
+
│ ConnRequest{proc, proto, src, dst, backend_id=客户端源端口}
|
|
360
|
+
▼
|
|
361
|
+
② rules.decide()(纯函数)→ DIRECT / BLOCK / PROXY
|
|
362
|
+
│ Decision{action, rule_id, upstream, reason}
|
|
363
|
+
▼
|
|
364
|
+
③ 先记账(SessionTable),再改道 —— 顺序不能反
|
|
365
|
+
│ 改写目的地址到 127.0.0.1:<sink>,并标记为回环、按出向回注
|
|
366
|
+
▼
|
|
367
|
+
④ Sink accept → 用「客户端源端口」反查回原始目标 → 选上游 → dial → relay
|
|
368
|
+
│
|
|
369
|
+
▼
|
|
370
|
+
⑤ UpstreamDialer(SOCKS5 / SOCKS4 / HTTP CONNECT / 跳链)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
反向路径同样要改:sink 的回应改写回"来自原始目标",否则三次握手完不成。
|
|
374
|
+
这两个方向 + 注入方式(源也要改成回环、按出向注入)是这条路线最容易踩的坑。
|
|
375
|
+
|
|
376
|
+
**分层**:`backend` 只管"捞进来 + 改道",`rules` 只管"该不该走代理"(纯函数、可单测),
|
|
377
|
+
`sink/relay` 只管"搬字节",`upstream` 只管"怎么跟代理服务器说话"。
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## 目录
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
procproxy.py 唯一入口(薄壳:挂 sys.path + 转发给 cli)
|
|
385
|
+
AGENTS.md 接口文档(给 AI / 程序化调用:SDK 用法 + 硬约束 + 禁区)
|
|
386
|
+
src/proxycore/ 核心包
|
|
387
|
+
├── rules.py 规则引擎(纯函数)
|
|
388
|
+
├── runtime.py 装配:后端 + 规则 + 会话表 + sink
|
|
389
|
+
├── backend/windivert 路线 A:WinDivert 抓包 / 改写 / 回注
|
|
390
|
+
├── tunnel/ sink + relay(本地落地与双向转发)
|
|
391
|
+
├── upstream/ SOCKS5 / SOCKS4 / HTTP CONNECT / 跳链
|
|
392
|
+
├── dns/ DNS 三模式与 UDP
|
|
393
|
+
├── forward.py ← procproxy.py <进程名> 的实现
|
|
394
|
+
├── canproxy.py / checkroute.py / probe.py / pathsetup.py ← 其余子命令
|
|
395
|
+
└── service/ ipc.py Windows 服务 + 命名管道
|
|
396
|
+
samples/ mock 服务 + 示例配置
|
|
397
|
+
docs/ 文档(00 架构与阅读路线 / 07 规则语义 / 11 排错 / 14 转发到抓包工具)
|
|
398
|
+
tests/ 测试套件(555 passed)
|
|
399
|
+
└── tools/ 验证脚本(run_demo / run_e2e / bench / …)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## 边界与已知限制
|
|
405
|
+
|
|
406
|
+
| 限制 | 说明 |
|
|
407
|
+
|---|---|
|
|
408
|
+
| **不捕获 UDP** | 过滤器以 `tcp` 开头。`udp_policy`(含 `443: block` 拦 QUIC)在本后端**整体空转** |
|
|
409
|
+
| **`dst_name` 规则永不命中** | 抓包式后端只拿得到 IP,拿不到域名 |
|
|
410
|
+
| **不解密** | HTTPS 是密文;要明文请转发给抓包工具 |
|
|
411
|
+
| **需要管理员** | WinDivert 内核驱动只能由管理员加载 |
|
|
412
|
+
| **上游端点必须写 IP 字面量** | 环路守卫按 `(host, port)` **字面量**比对;写 `localhost` 护栏就形同虚设 |
|
|
413
|
+
| **`unknown_pid`** | 本后端靠 `GetExtendedTcpTable` 查 PID,SYN 刚发出时可能查不到(竞态)。比例偏高时把 `on_unknown_pid` 改成 `block` |
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## 排错
|
|
418
|
+
|
|
419
|
+
见 [`docs/11-调试排错手册.md`](docs/11-调试排错手册.md)(症状 → 定位 → 解决)。
|
|
420
|
+
|
|
421
|
+
最常见的一条:**`[WinError 5] 拒绝访问` = 不是管理员**。
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## 开发
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
pip install -e ".[dev]"
|
|
429
|
+
python -m pytest -q tests/ # 555 passed / 4 skipped(非管理员 Windows)
|
|
430
|
+
python -m ruff check src tests
|
|
431
|
+
python -m mypy src/proxycore
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
验证脚本住在 `tests/tools/`(它们设计成独立可跑):
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
python tests/tools/run_demo.py # 15 组自检
|
|
438
|
+
python tests/tools/bench.py connect # 连接延迟
|
|
439
|
+
python tests/tools/real_machine_check.py # 真机改道(需管理员)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 第三方组件与许可证
|
|
445
|
+
|
|
446
|
+
本项目自身以 **MIT** 许可证发布,全文见 [`LICENSE`](LICENSE)。
|
|
447
|
+
|
|
448
|
+
第三方组件:
|
|
449
|
+
|
|
450
|
+
| 组件 | 许可证 | 说明 |
|
|
451
|
+
|---|---|---|
|
|
452
|
+
| [pydivert](https://github.com/ffalcinelli/pydivert) | **LGPLv3+ / GPLv2+**(双许可) | 见下方说明 |
|
|
453
|
+
| [WinDivert](https://github.com/basil00/WinDivert) | **LGPLv3** | 已签名内核驱动打包在 pydivert 的 wheel 内,由后者随附 |
|
|
454
|
+
| [PyYAML](https://pyyaml.org/) | MIT | 必需依赖 |
|
|
455
|
+
| [psutil](https://github.com/giampaolo/psutil) | BSD-3-Clause | `windivert` 可选依赖 |
|
|
456
|
+
| [pywin32](https://github.com/mhammond/pywin32) | PSF | Windows 服务包装,可选 |
|
|
457
|
+
| [keyring](https://github.com/jaraco/keyring) | MIT | `password_ref: "keyring:..."` 用,可选 |
|
|
458
|
+
|
|
459
|
+
### 关于 pydivert 的 LGPL
|
|
460
|
+
|
|
461
|
+
**默认情况下不触发任何 LGPL 义务**:本项目不打包、不内联 pydivert,
|
|
462
|
+
只声明依赖;用户从 PyPI 自行安装,分发者不是本项目。
|
|
463
|
+
LGPL 的义务绑定在「分发该库」这个动作上。
|
|
464
|
+
|
|
465
|
+
**打包成 exe 分发时**才需要满足三条:随附 LGPLv3 全文、提供源码获取途径、
|
|
466
|
+
允许用户替换该库。(pydivert 的 `dist-info/licenses/` 内已带全文。)
|
|
467
|
+
|
|
468
|
+
注:LGPL 不传染本项目自身的代码 —— 这正是它与 GPL 的区别。
|
|
469
|
+
|
|
470
|
+
### 使用须知
|
|
471
|
+
|
|
472
|
+
* 本工具会**拦截并转发本机网络流量**,需要管理员权限与内核驱动。
|
|
473
|
+
* **仅在你自有或已获授权的设备与网络上使用。**
|
|
474
|
+
* 使用代理可能违反你所在组织的网络策略或服务条款 —— 由使用者自行确认授权。
|
|
475
|
+
* 默认**不上报任何遥测**。默认不代理回环/私网。
|
|
476
|
+
|
|
477
|
+
### 独立实现与商标声明
|
|
478
|
+
|
|
479
|
+
本项目是独立的进程级代理实现,与 Proxifier 的权利人无任何关联,未获其授权或背书。
|
|
480
|
+
`Proxifier` 是其权利人的商标,本项目仅在兼容性/迁移说明中作指称使用。
|
|
481
|
+
本项目不包含、不解析 Proxifier 的私有文件格式或代码,也不提供任何绕过授权/DRM 的功能。
|
|
482
|
+
使用者应自行确认所在司法辖区的法律与软件许可协议(EULA)约束。
|
|
483
|
+
|
|
484
|
+
### AI 辅助开发说明
|
|
485
|
+
|
|
486
|
+
本项目在 AI 编程助手辅助下开发;需求、设计、取舍、测试与发布由人类作者负责。
|
|
487
|
+
代码来源审查未发现从第三方闭源产品复制的内容;AI 辅助与“复制反编译代码”是两件事。
|
|
488
|
+
AI 输出在部分司法辖区可能不具备可版权性,或与训练数据中的代码存在相似之处;
|
|
489
|
+
本项目按 MIT 许可证提供,不作额外保证,使用者应自行评估适用性与合规性。
|