procproxy 0.1.2__tar.gz → 0.1.3__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.2/src/procproxy.egg-info → procproxy-0.1.3}/PKG-INFO +54 -8
- {procproxy-0.1.2 → procproxy-0.1.3}/README.md +53 -7
- {procproxy-0.1.2 → procproxy-0.1.3}/pyproject.toml +1 -1
- {procproxy-0.1.2 → procproxy-0.1.3/src/procproxy.egg-info}/PKG-INFO +54 -8
- {procproxy-0.1.2 → procproxy-0.1.3}/src/procproxy.egg-info/SOURCES.txt +1 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/__init__.py +1 -1
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/api.py +30 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/cli.py +26 -30
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/config.py +2 -0
- procproxy-0.1.3/src/proxycore/config_init.py +85 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/LICENSE +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/setup.cfg +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/procproxy.egg-info/dependency_links.txt +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/procproxy.egg-info/entry_points.txt +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/procproxy.egg-info/requires.txt +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/procproxy.egg-info/top_level.txt +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/__main__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/__init__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/base.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/null.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/windivert/__init__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/windivert/filter.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/windivert/pidmap.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/backend/windivert/pkt.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/canproxy.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/checkroute.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/config_source.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/data/default.yaml +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/dns/__init__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/dns/cache.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/dns/modes.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/dns/udp.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/forward.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/ipc.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/log.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/pathsetup.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/probe.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/proc.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/rules.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/runtime.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/service/__init__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/service/__main__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/tunnel/__init__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/tunnel/relay.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/tunnel/sessions.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/tunnel/sink.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/types.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/upstream/__init__.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/upstream/base.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/upstream/chain.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/upstream/http_connect.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/upstream/socks4.py +0 -0
- {procproxy-0.1.2 → procproxy-0.1.3}/src/proxycore/upstream/socks5.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: procproxy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: ProcProxy —— 进程级代理:按进程决定哪条连接走哪个上游代理
|
|
5
5
|
Author: Longersking
|
|
6
6
|
License-Expression: MIT
|
|
@@ -74,7 +74,7 @@ python procproxy.py doctor | rules | sessions | ... # 子命令(等价于 pyt
|
|
|
74
74
|
pip install procproxy
|
|
75
75
|
procproxy init # 生成 ~/.procproxy/config.yaml
|
|
76
76
|
procproxy doctor # 环境自检
|
|
77
|
-
procproxy forward WeChat.exe --port 8848 # 真实转发(需管理员)
|
|
77
|
+
procproxy forward --process WeChat.exe --port 8848 # 真实转发(需管理员)
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
安装后直接运行 `procproxy` 会显示首次使用指引,不依赖任何样例文件。
|
|
@@ -250,7 +250,7 @@ python procproxy.py Weixin.exe WeChatAppEx.exe --port 8848
|
|
|
250
250
|
⚠️ 只有 ① 没有 ② → 端口填错了(**要填抓包工具的 MITM 监听口,不是它的 Web 管理口**)。
|
|
251
251
|
① ② 都正常但内容看不懂 → 那是 TLS,不是转发的问题。
|
|
252
252
|
|
|
253
|
-
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](docs/14
|
|
253
|
+
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](https://github.com/Longersking/procproxy/blob/master/docs/14-%E6%8A%8A%E8%BF%9B%E7%A8%8B%E6%B5%81%E9%87%8F%E8%BD%AC%E5%8F%91%E7%BB%99%E6%8A%93%E5%8C%85%E5%B7%A5%E5%85%B7.md)。
|
|
254
254
|
|
|
255
255
|
---
|
|
256
256
|
|
|
@@ -340,14 +340,14 @@ rules: # 自上而下,**首个命中生
|
|
|
340
340
|
7. 都没命中 → profile.default_action
|
|
341
341
|
```
|
|
342
342
|
|
|
343
|
-
完整语义见 [`docs/07-规则引擎与Profile格式.md`](docs/07
|
|
343
|
+
完整语义见 [`docs/07-规则引擎与Profile格式.md`](https://github.com/Longersking/procproxy/blob/master/docs/07-%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E4%B8%8EProfile%E6%A0%BC%E5%BC%8F.md)。
|
|
344
344
|
|
|
345
345
|
---
|
|
346
346
|
|
|
347
347
|
## 编程接口
|
|
348
348
|
|
|
349
349
|
`proxycore.api` 是与 CLI 共用同一套配置、规则引擎和会话表的 SDK。
|
|
350
|
-
完整教程见 [`docs/15-编程接口与SDK.md`](docs/15
|
|
350
|
+
完整教程见 [`docs/15-编程接口与SDK.md`](https://github.com/Longersking/procproxy/blob/master/docs/15-%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E4%B8%8ESDK.md)。
|
|
351
351
|
|
|
352
352
|
### 30 秒:零配置启动
|
|
353
353
|
|
|
@@ -373,6 +373,52 @@ with start_proxy() as ppx: # 不需要任何配置文件
|
|
|
373
373
|
状态查询和联调;要真实抓包请用 `backend="windivert"`(需管理员)或
|
|
374
374
|
`procproxy init` 生成自己的配置。
|
|
375
375
|
|
|
376
|
+
### 初始化:生成一份可编辑配置
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
from proxycore.api import init_config
|
|
380
|
+
|
|
381
|
+
path = init_config(
|
|
382
|
+
"D:/cfg/procproxy.yaml", # 省略则用 PROCPROXY_CONFIG 或 ~/.procproxy/config.yaml
|
|
383
|
+
backend="windivert", # 真抓包需管理员;联调用 "null"
|
|
384
|
+
sink_port=19080,
|
|
385
|
+
)
|
|
386
|
+
print(path) # 绝对路径;等价于 procproxy init
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
生成的是最小模板,`upstreams` / `rules` 仍为空,需要按下面的案例补上。
|
|
390
|
+
|
|
391
|
+
### 代理一个进程(最小完整配置)
|
|
392
|
+
|
|
393
|
+
```yaml
|
|
394
|
+
version: 1
|
|
395
|
+
service:
|
|
396
|
+
sink: { host: 127.0.0.1, port: 19080 }
|
|
397
|
+
backend: windivert # 真抓包;联调改 null
|
|
398
|
+
profile:
|
|
399
|
+
name: chrome-via-socks
|
|
400
|
+
default_action: direct
|
|
401
|
+
dns_mode: remote
|
|
402
|
+
upstreams:
|
|
403
|
+
- { alias: socks, kind: socks5, host: 127.0.0.1, port: 1080, auth: none }
|
|
404
|
+
rules:
|
|
405
|
+
- { id: r-private, action: direct, targets: "*",
|
|
406
|
+
dst_ip: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8" }
|
|
407
|
+
- { id: r-chrome, action: proxy, upstream: socks,
|
|
408
|
+
targets: "chrome.exe", dst_port: "*" }
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
from proxycore.api import start_proxy
|
|
413
|
+
|
|
414
|
+
with start_proxy("D:/cfg/chrome.yaml") as ppx: # 管理员终端
|
|
415
|
+
print(ppx.status())
|
|
416
|
+
print(ppx.sessions(limit=20))
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
规则自上而下、首个命中生效;启动后只影响**新建立**的连接。
|
|
420
|
+
完整步骤、验证方法与常见坑见 [`docs/15-编程接口与SDK.md`](https://github.com/Longersking/procproxy/blob/master/docs/15-%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E4%B8%8ESDK.md)。
|
|
421
|
+
|
|
376
422
|
### 显式配置与测试转发
|
|
377
423
|
|
|
378
424
|
```python
|
|
@@ -541,7 +587,7 @@ src/proxycore/ 核心包
|
|
|
541
587
|
└── service/ ipc.py Windows 服务 + 命名管道
|
|
542
588
|
samples/ mock 服务 + 示例配置
|
|
543
589
|
docs/ 文档(00 架构 / 07 规则 / 11 排错 / 14 抓包 / 15 SDK)
|
|
544
|
-
tests/ 测试套件(
|
|
590
|
+
tests/ 测试套件(624 passed / 4 skipped)
|
|
545
591
|
└── tools/ 验证脚本(run_demo / run_e2e / bench / …)
|
|
546
592
|
```
|
|
547
593
|
|
|
@@ -562,7 +608,7 @@ tests/ 测试套件(619 passed / 4 skipped)
|
|
|
562
608
|
|
|
563
609
|
## 排错
|
|
564
610
|
|
|
565
|
-
见 [`docs/11-调试排错手册.md`](docs/11
|
|
611
|
+
见 [`docs/11-调试排错手册.md`](https://github.com/Longersking/procproxy/blob/master/docs/11-%E8%B0%83%E8%AF%95%E6%8E%92%E9%94%99%E6%89%8B%E5%86%8C.md)(症状 → 定位 → 解决)。
|
|
566
612
|
|
|
567
613
|
最常见的一条:**`[WinError 5] 拒绝访问` = 不是管理员**。
|
|
568
614
|
|
|
@@ -572,7 +618,7 @@ tests/ 测试套件(619 passed / 4 skipped)
|
|
|
572
618
|
|
|
573
619
|
```bash
|
|
574
620
|
pip install -e ".[dev]"
|
|
575
|
-
python -m pytest -q tests/ #
|
|
621
|
+
python -m pytest -q tests/ # 624 passed / 4 skipped(非管理员 Windows)
|
|
576
622
|
python -m ruff check src tests
|
|
577
623
|
python -m mypy src/proxycore
|
|
578
624
|
```
|
|
@@ -35,7 +35,7 @@ python procproxy.py doctor | rules | sessions | ... # 子命令(等价于 pyt
|
|
|
35
35
|
pip install procproxy
|
|
36
36
|
procproxy init # 生成 ~/.procproxy/config.yaml
|
|
37
37
|
procproxy doctor # 环境自检
|
|
38
|
-
procproxy forward WeChat.exe --port 8848 # 真实转发(需管理员)
|
|
38
|
+
procproxy forward --process WeChat.exe --port 8848 # 真实转发(需管理员)
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
安装后直接运行 `procproxy` 会显示首次使用指引,不依赖任何样例文件。
|
|
@@ -211,7 +211,7 @@ python procproxy.py Weixin.exe WeChatAppEx.exe --port 8848
|
|
|
211
211
|
⚠️ 只有 ① 没有 ② → 端口填错了(**要填抓包工具的 MITM 监听口,不是它的 Web 管理口**)。
|
|
212
212
|
① ② 都正常但内容看不懂 → 那是 TLS,不是转发的问题。
|
|
213
213
|
|
|
214
|
-
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](docs/14
|
|
214
|
+
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](https://github.com/Longersking/procproxy/blob/master/docs/14-%E6%8A%8A%E8%BF%9B%E7%A8%8B%E6%B5%81%E9%87%8F%E8%BD%AC%E5%8F%91%E7%BB%99%E6%8A%93%E5%8C%85%E5%B7%A5%E5%85%B7.md)。
|
|
215
215
|
|
|
216
216
|
---
|
|
217
217
|
|
|
@@ -301,14 +301,14 @@ rules: # 自上而下,**首个命中生
|
|
|
301
301
|
7. 都没命中 → profile.default_action
|
|
302
302
|
```
|
|
303
303
|
|
|
304
|
-
完整语义见 [`docs/07-规则引擎与Profile格式.md`](docs/07
|
|
304
|
+
完整语义见 [`docs/07-规则引擎与Profile格式.md`](https://github.com/Longersking/procproxy/blob/master/docs/07-%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E4%B8%8EProfile%E6%A0%BC%E5%BC%8F.md)。
|
|
305
305
|
|
|
306
306
|
---
|
|
307
307
|
|
|
308
308
|
## 编程接口
|
|
309
309
|
|
|
310
310
|
`proxycore.api` 是与 CLI 共用同一套配置、规则引擎和会话表的 SDK。
|
|
311
|
-
完整教程见 [`docs/15-编程接口与SDK.md`](docs/15
|
|
311
|
+
完整教程见 [`docs/15-编程接口与SDK.md`](https://github.com/Longersking/procproxy/blob/master/docs/15-%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E4%B8%8ESDK.md)。
|
|
312
312
|
|
|
313
313
|
### 30 秒:零配置启动
|
|
314
314
|
|
|
@@ -334,6 +334,52 @@ with start_proxy() as ppx: # 不需要任何配置文件
|
|
|
334
334
|
状态查询和联调;要真实抓包请用 `backend="windivert"`(需管理员)或
|
|
335
335
|
`procproxy init` 生成自己的配置。
|
|
336
336
|
|
|
337
|
+
### 初始化:生成一份可编辑配置
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
from proxycore.api import init_config
|
|
341
|
+
|
|
342
|
+
path = init_config(
|
|
343
|
+
"D:/cfg/procproxy.yaml", # 省略则用 PROCPROXY_CONFIG 或 ~/.procproxy/config.yaml
|
|
344
|
+
backend="windivert", # 真抓包需管理员;联调用 "null"
|
|
345
|
+
sink_port=19080,
|
|
346
|
+
)
|
|
347
|
+
print(path) # 绝对路径;等价于 procproxy init
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
生成的是最小模板,`upstreams` / `rules` 仍为空,需要按下面的案例补上。
|
|
351
|
+
|
|
352
|
+
### 代理一个进程(最小完整配置)
|
|
353
|
+
|
|
354
|
+
```yaml
|
|
355
|
+
version: 1
|
|
356
|
+
service:
|
|
357
|
+
sink: { host: 127.0.0.1, port: 19080 }
|
|
358
|
+
backend: windivert # 真抓包;联调改 null
|
|
359
|
+
profile:
|
|
360
|
+
name: chrome-via-socks
|
|
361
|
+
default_action: direct
|
|
362
|
+
dns_mode: remote
|
|
363
|
+
upstreams:
|
|
364
|
+
- { alias: socks, kind: socks5, host: 127.0.0.1, port: 1080, auth: none }
|
|
365
|
+
rules:
|
|
366
|
+
- { id: r-private, action: direct, targets: "*",
|
|
367
|
+
dst_ip: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8" }
|
|
368
|
+
- { id: r-chrome, action: proxy, upstream: socks,
|
|
369
|
+
targets: "chrome.exe", dst_port: "*" }
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
from proxycore.api import start_proxy
|
|
374
|
+
|
|
375
|
+
with start_proxy("D:/cfg/chrome.yaml") as ppx: # 管理员终端
|
|
376
|
+
print(ppx.status())
|
|
377
|
+
print(ppx.sessions(limit=20))
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
规则自上而下、首个命中生效;启动后只影响**新建立**的连接。
|
|
381
|
+
完整步骤、验证方法与常见坑见 [`docs/15-编程接口与SDK.md`](https://github.com/Longersking/procproxy/blob/master/docs/15-%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E4%B8%8ESDK.md)。
|
|
382
|
+
|
|
337
383
|
### 显式配置与测试转发
|
|
338
384
|
|
|
339
385
|
```python
|
|
@@ -502,7 +548,7 @@ src/proxycore/ 核心包
|
|
|
502
548
|
└── service/ ipc.py Windows 服务 + 命名管道
|
|
503
549
|
samples/ mock 服务 + 示例配置
|
|
504
550
|
docs/ 文档(00 架构 / 07 规则 / 11 排错 / 14 抓包 / 15 SDK)
|
|
505
|
-
tests/ 测试套件(
|
|
551
|
+
tests/ 测试套件(624 passed / 4 skipped)
|
|
506
552
|
└── tools/ 验证脚本(run_demo / run_e2e / bench / …)
|
|
507
553
|
```
|
|
508
554
|
|
|
@@ -523,7 +569,7 @@ tests/ 测试套件(619 passed / 4 skipped)
|
|
|
523
569
|
|
|
524
570
|
## 排错
|
|
525
571
|
|
|
526
|
-
见 [`docs/11-调试排错手册.md`](docs/11
|
|
572
|
+
见 [`docs/11-调试排错手册.md`](https://github.com/Longersking/procproxy/blob/master/docs/11-%E8%B0%83%E8%AF%95%E6%8E%92%E9%94%99%E6%89%8B%E5%86%8C.md)(症状 → 定位 → 解决)。
|
|
527
573
|
|
|
528
574
|
最常见的一条:**`[WinError 5] 拒绝访问` = 不是管理员**。
|
|
529
575
|
|
|
@@ -533,7 +579,7 @@ tests/ 测试套件(619 passed / 4 skipped)
|
|
|
533
579
|
|
|
534
580
|
```bash
|
|
535
581
|
pip install -e ".[dev]"
|
|
536
|
-
python -m pytest -q tests/ #
|
|
582
|
+
python -m pytest -q tests/ # 624 passed / 4 skipped(非管理员 Windows)
|
|
537
583
|
python -m ruff check src tests
|
|
538
584
|
python -m mypy src/proxycore
|
|
539
585
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: procproxy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: ProcProxy —— 进程级代理:按进程决定哪条连接走哪个上游代理
|
|
5
5
|
Author: Longersking
|
|
6
6
|
License-Expression: MIT
|
|
@@ -74,7 +74,7 @@ python procproxy.py doctor | rules | sessions | ... # 子命令(等价于 pyt
|
|
|
74
74
|
pip install procproxy
|
|
75
75
|
procproxy init # 生成 ~/.procproxy/config.yaml
|
|
76
76
|
procproxy doctor # 环境自检
|
|
77
|
-
procproxy forward WeChat.exe --port 8848 # 真实转发(需管理员)
|
|
77
|
+
procproxy forward --process WeChat.exe --port 8848 # 真实转发(需管理员)
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
安装后直接运行 `procproxy` 会显示首次使用指引,不依赖任何样例文件。
|
|
@@ -250,7 +250,7 @@ python procproxy.py Weixin.exe WeChatAppEx.exe --port 8848
|
|
|
250
250
|
⚠️ 只有 ① 没有 ② → 端口填错了(**要填抓包工具的 MITM 监听口,不是它的 Web 管理口**)。
|
|
251
251
|
① ② 都正常但内容看不懂 → 那是 TLS,不是转发的问题。
|
|
252
252
|
|
|
253
|
-
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](docs/14
|
|
253
|
+
完整指南(含排错与参数表)见 [`docs/14-把进程流量转发给抓包工具.md`](https://github.com/Longersking/procproxy/blob/master/docs/14-%E6%8A%8A%E8%BF%9B%E7%A8%8B%E6%B5%81%E9%87%8F%E8%BD%AC%E5%8F%91%E7%BB%99%E6%8A%93%E5%8C%85%E5%B7%A5%E5%85%B7.md)。
|
|
254
254
|
|
|
255
255
|
---
|
|
256
256
|
|
|
@@ -340,14 +340,14 @@ rules: # 自上而下,**首个命中生
|
|
|
340
340
|
7. 都没命中 → profile.default_action
|
|
341
341
|
```
|
|
342
342
|
|
|
343
|
-
完整语义见 [`docs/07-规则引擎与Profile格式.md`](docs/07
|
|
343
|
+
完整语义见 [`docs/07-规则引擎与Profile格式.md`](https://github.com/Longersking/procproxy/blob/master/docs/07-%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E4%B8%8EProfile%E6%A0%BC%E5%BC%8F.md)。
|
|
344
344
|
|
|
345
345
|
---
|
|
346
346
|
|
|
347
347
|
## 编程接口
|
|
348
348
|
|
|
349
349
|
`proxycore.api` 是与 CLI 共用同一套配置、规则引擎和会话表的 SDK。
|
|
350
|
-
完整教程见 [`docs/15-编程接口与SDK.md`](docs/15
|
|
350
|
+
完整教程见 [`docs/15-编程接口与SDK.md`](https://github.com/Longersking/procproxy/blob/master/docs/15-%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E4%B8%8ESDK.md)。
|
|
351
351
|
|
|
352
352
|
### 30 秒:零配置启动
|
|
353
353
|
|
|
@@ -373,6 +373,52 @@ with start_proxy() as ppx: # 不需要任何配置文件
|
|
|
373
373
|
状态查询和联调;要真实抓包请用 `backend="windivert"`(需管理员)或
|
|
374
374
|
`procproxy init` 生成自己的配置。
|
|
375
375
|
|
|
376
|
+
### 初始化:生成一份可编辑配置
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
from proxycore.api import init_config
|
|
380
|
+
|
|
381
|
+
path = init_config(
|
|
382
|
+
"D:/cfg/procproxy.yaml", # 省略则用 PROCPROXY_CONFIG 或 ~/.procproxy/config.yaml
|
|
383
|
+
backend="windivert", # 真抓包需管理员;联调用 "null"
|
|
384
|
+
sink_port=19080,
|
|
385
|
+
)
|
|
386
|
+
print(path) # 绝对路径;等价于 procproxy init
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
生成的是最小模板,`upstreams` / `rules` 仍为空,需要按下面的案例补上。
|
|
390
|
+
|
|
391
|
+
### 代理一个进程(最小完整配置)
|
|
392
|
+
|
|
393
|
+
```yaml
|
|
394
|
+
version: 1
|
|
395
|
+
service:
|
|
396
|
+
sink: { host: 127.0.0.1, port: 19080 }
|
|
397
|
+
backend: windivert # 真抓包;联调改 null
|
|
398
|
+
profile:
|
|
399
|
+
name: chrome-via-socks
|
|
400
|
+
default_action: direct
|
|
401
|
+
dns_mode: remote
|
|
402
|
+
upstreams:
|
|
403
|
+
- { alias: socks, kind: socks5, host: 127.0.0.1, port: 1080, auth: none }
|
|
404
|
+
rules:
|
|
405
|
+
- { id: r-private, action: direct, targets: "*",
|
|
406
|
+
dst_ip: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8" }
|
|
407
|
+
- { id: r-chrome, action: proxy, upstream: socks,
|
|
408
|
+
targets: "chrome.exe", dst_port: "*" }
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
from proxycore.api import start_proxy
|
|
413
|
+
|
|
414
|
+
with start_proxy("D:/cfg/chrome.yaml") as ppx: # 管理员终端
|
|
415
|
+
print(ppx.status())
|
|
416
|
+
print(ppx.sessions(limit=20))
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
规则自上而下、首个命中生效;启动后只影响**新建立**的连接。
|
|
420
|
+
完整步骤、验证方法与常见坑见 [`docs/15-编程接口与SDK.md`](https://github.com/Longersking/procproxy/blob/master/docs/15-%E7%BC%96%E7%A8%8B%E6%8E%A5%E5%8F%A3%E4%B8%8ESDK.md)。
|
|
421
|
+
|
|
376
422
|
### 显式配置与测试转发
|
|
377
423
|
|
|
378
424
|
```python
|
|
@@ -541,7 +587,7 @@ src/proxycore/ 核心包
|
|
|
541
587
|
└── service/ ipc.py Windows 服务 + 命名管道
|
|
542
588
|
samples/ mock 服务 + 示例配置
|
|
543
589
|
docs/ 文档(00 架构 / 07 规则 / 11 排错 / 14 抓包 / 15 SDK)
|
|
544
|
-
tests/ 测试套件(
|
|
590
|
+
tests/ 测试套件(624 passed / 4 skipped)
|
|
545
591
|
└── tools/ 验证脚本(run_demo / run_e2e / bench / …)
|
|
546
592
|
```
|
|
547
593
|
|
|
@@ -562,7 +608,7 @@ tests/ 测试套件(619 passed / 4 skipped)
|
|
|
562
608
|
|
|
563
609
|
## 排错
|
|
564
610
|
|
|
565
|
-
见 [`docs/11-调试排错手册.md`](docs/11
|
|
611
|
+
见 [`docs/11-调试排错手册.md`](https://github.com/Longersking/procproxy/blob/master/docs/11-%E8%B0%83%E8%AF%95%E6%8E%92%E9%94%99%E6%89%8B%E5%86%8C.md)(症状 → 定位 → 解决)。
|
|
566
612
|
|
|
567
613
|
最常见的一条:**`[WinError 5] 拒绝访问` = 不是管理员**。
|
|
568
614
|
|
|
@@ -572,7 +618,7 @@ tests/ 测试套件(619 passed / 4 skipped)
|
|
|
572
618
|
|
|
573
619
|
```bash
|
|
574
620
|
pip install -e ".[dev]"
|
|
575
|
-
python -m pytest -q tests/ #
|
|
621
|
+
python -m pytest -q tests/ # 624 passed / 4 skipped(非管理员 Windows)
|
|
576
622
|
python -m ruff check src tests
|
|
577
623
|
python -m mypy src/proxycore
|
|
578
624
|
```
|
|
@@ -50,6 +50,7 @@ from pathlib import Path
|
|
|
50
50
|
from typing import Any
|
|
51
51
|
|
|
52
52
|
from .config import Config, ConfigError, ConfigManager
|
|
53
|
+
from .config_init import create_config_file
|
|
53
54
|
from .config_source import ORIGIN_EXPLICIT, ORIGIN_OBJECT, normalize_config_path, resolve_config_source
|
|
54
55
|
from .log import EventLogger, build_logger, get_logger
|
|
55
56
|
from .runtime import Runtime
|
|
@@ -90,6 +91,34 @@ def load_config(
|
|
|
90
91
|
return config
|
|
91
92
|
|
|
92
93
|
|
|
94
|
+
def init_config(
|
|
95
|
+
path: str | os.PathLike[str] | None = None,
|
|
96
|
+
*,
|
|
97
|
+
backend: str = "null",
|
|
98
|
+
sink_port: int = 19080,
|
|
99
|
+
force: bool = False,
|
|
100
|
+
) -> Path:
|
|
101
|
+
"""从内置模板生成一份可编辑配置,返回绝对路径。
|
|
102
|
+
|
|
103
|
+
等价于 `procproxy init`,但可以在 Python 里调用:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from proxycore.api import init_config
|
|
107
|
+
|
|
108
|
+
path = init_config(backend="windivert", sink_port=19080)
|
|
109
|
+
# 之后编辑 path 里的 upstreams / rules,再用 start_proxy(path) 启动
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
* `path=None` → `PROCPROXY_CONFIG` 或 `~/.procproxy/config.yaml`;
|
|
113
|
+
* 目标已存在时默认拒绝覆盖(`config_exists`),`force=True` 才覆盖;
|
|
114
|
+
* 失败抛 `ProxyStartError`,`code` 同底层 `ConfigError.code`。
|
|
115
|
+
"""
|
|
116
|
+
try:
|
|
117
|
+
return create_config_file(path, backend=backend, sink_port=sink_port, force=force)
|
|
118
|
+
except ConfigError as exc:
|
|
119
|
+
raise _wrap_config_error(exc) from exc
|
|
120
|
+
|
|
121
|
+
|
|
93
122
|
def _resolve_and_load(
|
|
94
123
|
config: Config | str | os.PathLike[str] | None, *, check_sink: bool = False
|
|
95
124
|
) -> Config:
|
|
@@ -308,6 +337,7 @@ def run_forever(config: Config | str | os.PathLike[str] | None = None, **kwargs:
|
|
|
308
337
|
__all__ = [
|
|
309
338
|
"ProxyHandle",
|
|
310
339
|
"ProxyStartError",
|
|
340
|
+
"init_config",
|
|
311
341
|
"load_config",
|
|
312
342
|
"make_runtime",
|
|
313
343
|
"run_forever",
|
|
@@ -16,10 +16,17 @@ import time
|
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
|
-
import yaml
|
|
20
|
-
|
|
21
19
|
from proxycore import __version__
|
|
22
|
-
from proxycore.config import
|
|
20
|
+
from proxycore.config import (
|
|
21
|
+
E_CONFIG_ARGUMENT_INVALID,
|
|
22
|
+
E_CONFIG_EXISTS,
|
|
23
|
+
E_CONFIG_NOT_FOUND,
|
|
24
|
+
E_SINK_PORT_UNAVAILABLE,
|
|
25
|
+
Config,
|
|
26
|
+
ConfigError,
|
|
27
|
+
ConfigManager,
|
|
28
|
+
port_in_use,
|
|
29
|
+
)
|
|
23
30
|
from proxycore.config_source import (
|
|
24
31
|
DEFAULT_CONFIG,
|
|
25
32
|
ORIGIN_ENV,
|
|
@@ -243,36 +250,25 @@ def cmd_config(args: argparse.Namespace) -> int:
|
|
|
243
250
|
|
|
244
251
|
def cmd_init(args: argparse.Namespace) -> int:
|
|
245
252
|
"""生成一份可编辑的启动配置(PyPI 安装后首次使用)。"""
|
|
246
|
-
|
|
247
|
-
if target.exists() and not args.force:
|
|
248
|
-
print(f"配置文件已存在: {target}(加 --force 覆盖)", file=sys.stderr)
|
|
249
|
-
return 2
|
|
250
|
-
if not 1024 <= args.sink_port <= 65535:
|
|
251
|
-
print("--sink-port 必须在 1024-65535", file=sys.stderr)
|
|
252
|
-
return 2
|
|
253
|
-
packaged = packaged_default_config()
|
|
254
|
-
if packaged is None:
|
|
255
|
-
print("安装包缺少内置默认配置,请重新安装 procproxy", file=sys.stderr)
|
|
256
|
-
return 2
|
|
253
|
+
from proxycore.config_init import create_config_file
|
|
257
254
|
|
|
258
|
-
doc = yaml.safe_load(packaged.read_text(encoding="utf-8")) or {}
|
|
259
|
-
service = doc.setdefault("service", {})
|
|
260
|
-
service["backend"] = args.backend
|
|
261
|
-
sink = service.setdefault("sink", {})
|
|
262
|
-
sink.setdefault("host", "127.0.0.1")
|
|
263
|
-
sink["port"] = args.sink_port
|
|
264
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
265
|
-
header = "# ProcProxy 配置(由 `procproxy init` 生成)\n"
|
|
266
|
-
target.write_text(
|
|
267
|
-
header + yaml.safe_dump(doc, allow_unicode=True, sort_keys=False),
|
|
268
|
-
encoding="utf-8",
|
|
269
|
-
)
|
|
270
255
|
try:
|
|
271
|
-
|
|
256
|
+
target = create_config_file(
|
|
257
|
+
args.path or None,
|
|
258
|
+
backend=args.backend,
|
|
259
|
+
sink_port=args.sink_port,
|
|
260
|
+
force=args.force,
|
|
261
|
+
)
|
|
272
262
|
except ConfigError as exc:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
263
|
+
if exc.code in {
|
|
264
|
+
E_CONFIG_EXISTS,
|
|
265
|
+
E_CONFIG_NOT_FOUND,
|
|
266
|
+
E_SINK_PORT_UNAVAILABLE,
|
|
267
|
+
E_CONFIG_ARGUMENT_INVALID,
|
|
268
|
+
}:
|
|
269
|
+
print(exc.message, file=sys.stderr)
|
|
270
|
+
else:
|
|
271
|
+
print(f"生成的配置未通过校验:{exc.code} — {exc.message}", file=sys.stderr)
|
|
276
272
|
return 2
|
|
277
273
|
|
|
278
274
|
print(f"已生成配置: {target}")
|
|
@@ -44,6 +44,8 @@ E_PROFILE_OPTION_UNSUPPORTED = "profile_option_unsupported"
|
|
|
44
44
|
E_CONFIG_NOT_FOUND = "config_not_found"
|
|
45
45
|
E_CONFIG_UNREADABLE = "config_unreadable"
|
|
46
46
|
E_CONFIG_PARSE_INVALID = "config_parse_invalid"
|
|
47
|
+
E_CONFIG_EXISTS = "config_exists"
|
|
48
|
+
E_CONFIG_ARGUMENT_INVALID = "config_invalid_argument"
|
|
47
49
|
# 运行时错误码
|
|
48
50
|
E_BACKEND_UNAVAILABLE = "E_BACKEND_UNAVAILABLE"
|
|
49
51
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""生成一份可编辑的启动配置(CLI `init` 与 Python `api.init_config` 共用)。
|
|
2
|
+
|
|
3
|
+
模板来自安装包里的 `data/default.yaml`,只覆盖 backend 与 sink 端口;
|
|
4
|
+
upstreams / rules 留空,由用户或调用方按需填写。写入后立刻用
|
|
5
|
+
`Config.load` 校验,失败则删除半成品文件。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import yaml
|
|
14
|
+
|
|
15
|
+
from .config import (
|
|
16
|
+
E_CONFIG_ARGUMENT_INVALID,
|
|
17
|
+
E_CONFIG_EXISTS,
|
|
18
|
+
E_CONFIG_NOT_FOUND,
|
|
19
|
+
E_CONFIG_UNREADABLE,
|
|
20
|
+
E_SINK_PORT_UNAVAILABLE,
|
|
21
|
+
Config,
|
|
22
|
+
ConfigError,
|
|
23
|
+
)
|
|
24
|
+
from .config_source import packaged_default_config, user_config_path
|
|
25
|
+
|
|
26
|
+
VALID_BACKENDS = ("null", "windivert")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_config_file(
|
|
30
|
+
path: str | os.PathLike[str] | None = None,
|
|
31
|
+
*,
|
|
32
|
+
backend: str = "null",
|
|
33
|
+
sink_port: int = 19080,
|
|
34
|
+
force: bool = False,
|
|
35
|
+
) -> Path:
|
|
36
|
+
"""从内置模板生成配置文件,返回绝对路径。
|
|
37
|
+
|
|
38
|
+
* `path=None`:写到 `PROCPROXY_CONFIG` 或 `~/.procproxy/config.yaml`;
|
|
39
|
+
* `force=False`:目标已存在时抛 `config_exists`,绝不覆盖;
|
|
40
|
+
* `backend`:`null`(联调)或 `windivert`(真抓包,需管理员);
|
|
41
|
+
* 生成后立即校验,校验失败会删除文件并抛出原始 `ConfigError`。
|
|
42
|
+
"""
|
|
43
|
+
target = (Path(path) if path else user_config_path()).expanduser()
|
|
44
|
+
target = (Path.cwd() / target).resolve() if not target.is_absolute() else target.resolve()
|
|
45
|
+
|
|
46
|
+
if target.exists() and not force:
|
|
47
|
+
raise ConfigError(E_CONFIG_EXISTS, f"配置文件已存在: {target}(force=True 覆盖)")
|
|
48
|
+
if backend not in VALID_BACKENDS:
|
|
49
|
+
raise ConfigError(
|
|
50
|
+
E_CONFIG_ARGUMENT_INVALID,
|
|
51
|
+
f"未知 backend {backend!r}(可选:{', '.join(VALID_BACKENDS)})",
|
|
52
|
+
)
|
|
53
|
+
if not 1024 <= sink_port <= 65535:
|
|
54
|
+
raise ConfigError(
|
|
55
|
+
E_SINK_PORT_UNAVAILABLE,
|
|
56
|
+
f"sink 端口必须在 1024-65535,当前 {sink_port}",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
packaged = packaged_default_config()
|
|
60
|
+
if packaged is None:
|
|
61
|
+
raise ConfigError(E_CONFIG_NOT_FOUND, "安装包缺少内置默认配置,请重新安装 procproxy")
|
|
62
|
+
|
|
63
|
+
doc = yaml.safe_load(packaged.read_text(encoding="utf-8")) or {}
|
|
64
|
+
service = doc.setdefault("service", {})
|
|
65
|
+
service["backend"] = backend
|
|
66
|
+
sink = service.setdefault("sink", {})
|
|
67
|
+
sink.setdefault("host", "127.0.0.1")
|
|
68
|
+
sink["port"] = sink_port
|
|
69
|
+
|
|
70
|
+
header = "# ProcProxy 配置(由 procproxy init / proxycore.api.init_config 生成)\n"
|
|
71
|
+
try:
|
|
72
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
target.write_text(
|
|
74
|
+
header + yaml.safe_dump(doc, allow_unicode=True, sort_keys=False),
|
|
75
|
+
encoding="utf-8",
|
|
76
|
+
)
|
|
77
|
+
except OSError as exc:
|
|
78
|
+
raise ConfigError(E_CONFIG_UNREADABLE, f"无法写入配置 {target}: {exc}") from exc
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
Config.load(target)
|
|
82
|
+
except ConfigError:
|
|
83
|
+
target.unlink(missing_ok=True)
|
|
84
|
+
raise
|
|
85
|
+
return target
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|