procproxy 0.1.1__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.1/src/procproxy.egg-info → procproxy-0.1.3}/PKG-INFO +194 -18
- {procproxy-0.1.1 → procproxy-0.1.3}/README.md +193 -17
- {procproxy-0.1.1 → procproxy-0.1.3}/pyproject.toml +1 -1
- {procproxy-0.1.1 → procproxy-0.1.3/src/procproxy.egg-info}/PKG-INFO +194 -18
- {procproxy-0.1.1 → procproxy-0.1.3}/src/procproxy.egg-info/SOURCES.txt +2 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/__init__.py +1 -1
- procproxy-0.1.3/src/proxycore/api.py +345 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/canproxy.py +22 -20
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/checkroute.py +14 -10
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/cli.py +81 -101
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/config.py +30 -6
- procproxy-0.1.3/src/proxycore/config_init.py +85 -0
- procproxy-0.1.3/src/proxycore/config_source.py +154 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/service/__init__.py +11 -2
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/service/__main__.py +19 -5
- procproxy-0.1.1/src/proxycore/api.py +0 -226
- {procproxy-0.1.1 → procproxy-0.1.3}/LICENSE +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/setup.cfg +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/procproxy.egg-info/dependency_links.txt +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/procproxy.egg-info/entry_points.txt +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/procproxy.egg-info/requires.txt +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/procproxy.egg-info/top_level.txt +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/__main__.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/__init__.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/base.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/null.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/windivert/__init__.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/windivert/filter.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/windivert/pidmap.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/backend/windivert/pkt.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/data/default.yaml +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/dns/__init__.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/dns/cache.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/dns/modes.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/dns/udp.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/forward.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/ipc.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/log.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/pathsetup.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/probe.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/proc.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/rules.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/runtime.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/tunnel/__init__.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/tunnel/relay.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/tunnel/sessions.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/tunnel/sink.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/types.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/upstream/__init__.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/upstream/base.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/upstream/chain.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/upstream/http_connect.py +0 -0
- {procproxy-0.1.1 → procproxy-0.1.3}/src/proxycore/upstream/socks4.py +0 -0
- {procproxy-0.1.1 → 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,10 +74,12 @@ 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` 会显示首次使用指引,不依赖任何样例文件。
|
|
81
|
+
Python SDK 也一样:`start_proxy()` 不传配置即可启动(内置 `backend=null`),
|
|
82
|
+
不需要先跑 `init`;`init` 只用于生成可编辑配置。
|
|
81
83
|
|
|
82
84
|
非管理员:WinDivert 抓包必须管理员;可以用 `--backend null` 做转发链路联调,
|
|
83
85
|
或在服务已启动、且配置了 `service.ipc_allow_group` 时读取状态。
|
|
@@ -248,7 +250,7 @@ python procproxy.py Weixin.exe WeChatAppEx.exe --port 8848
|
|
|
248
250
|
⚠️ 只有 ① 没有 ② → 端口填错了(**要填抓包工具的 MITM 监听口,不是它的 Web 管理口**)。
|
|
249
251
|
① ② 都正常但内容看不懂 → 那是 TLS,不是转发的问题。
|
|
250
252
|
|
|
251
|
-
完整指南(含排错与参数表)见 [`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)。
|
|
252
254
|
|
|
253
255
|
---
|
|
254
256
|
|
|
@@ -338,30 +340,203 @@ rules: # 自上而下,**首个命中生
|
|
|
338
340
|
7. 都没命中 → profile.default_action
|
|
339
341
|
```
|
|
340
342
|
|
|
341
|
-
完整语义见 [`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)。
|
|
342
344
|
|
|
343
345
|
---
|
|
344
346
|
|
|
345
347
|
## 编程接口
|
|
346
348
|
|
|
349
|
+
`proxycore.api` 是与 CLI 共用同一套配置、规则引擎和会话表的 SDK。
|
|
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
|
+
|
|
352
|
+
### 30 秒:零配置启动
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
from proxycore.api import start_proxy
|
|
356
|
+
|
|
357
|
+
with start_proxy() as ppx: # 不需要任何配置文件
|
|
358
|
+
print(ppx.config_source) # "packaged"
|
|
359
|
+
print(ppx.config_path) # .../proxycore/data/default.yaml
|
|
360
|
+
print(ppx.status()) # 后端 / 规则 / 会话 / UDP / 配置来源
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
不传配置时的来源优先级:
|
|
364
|
+
|
|
365
|
+
| 优先级 | 来源 | 说明 |
|
|
366
|
+
|---|---|---|
|
|
367
|
+
| 1 | `start_proxy(path)` | 显式路径(也接受内存中的 `Config` 对象) |
|
|
368
|
+
| 2 | `PROCPROXY_CONFIG` | 指向不存在文件会直接报错,不回退 |
|
|
369
|
+
| 3 | `~/.procproxy/config.yaml` | `procproxy init` 生成的用户配置 |
|
|
370
|
+
| 4 | 包内 `data/default.yaml` | `backend=null`,不抓包、不改道 |
|
|
371
|
+
|
|
372
|
+
内置配置**不会**监听 sink,也**不会**创建任何文件。它适合装配、规则决策、
|
|
373
|
+
状态查询和联调;要真实抓包请用 `backend="windivert"`(需管理员)或
|
|
374
|
+
`procproxy init` 生成自己的配置。
|
|
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
|
+
|
|
347
411
|
```python
|
|
348
|
-
from proxycore import
|
|
412
|
+
from proxycore.api import start_proxy
|
|
349
413
|
|
|
350
|
-
#
|
|
351
|
-
|
|
352
|
-
print(
|
|
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)。
|
|
353
421
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
422
|
+
### 显式配置与测试转发
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
from proxycore.api import start_proxy
|
|
426
|
+
|
|
427
|
+
# 显式路径 + 真实抓包(需要管理员)
|
|
428
|
+
with start_proxy(r"D:\cfg\procproxy.yaml", backend="windivert") as ppx:
|
|
429
|
+
print(ppx.sink) # sink 监听地址
|
|
430
|
+
print(ppx.sessions(limit=20))
|
|
431
|
+
|
|
432
|
+
# 联调模式:backend=null + 把 sink 收到的连接固定转发到目标
|
|
433
|
+
with start_proxy(backend="null", sink_test_target="127.0.0.1:8080",
|
|
434
|
+
upstream="local-mock") as ppx:
|
|
357
435
|
...
|
|
436
|
+
# curl -x http://127.0.0.1:19080 http://any/ → 127.0.0.1:8080
|
|
437
|
+
```
|
|
358
438
|
|
|
359
|
-
|
|
360
|
-
|
|
439
|
+
### 在代码里构建配置
|
|
440
|
+
|
|
441
|
+
可以从字典构造 `Config`,也可以先落盘再按路径加载:
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from proxycore.config import Config, atomic_write
|
|
445
|
+
from proxycore.api import start_proxy
|
|
446
|
+
|
|
447
|
+
doc = {
|
|
448
|
+
"version": 1,
|
|
449
|
+
"service": {"sink": {"host": "127.0.0.1", "port": 19080}, "backend": "null"},
|
|
450
|
+
"profile": {
|
|
451
|
+
"name": "myapp",
|
|
452
|
+
"default_action": "direct",
|
|
453
|
+
"dns_mode": "remote",
|
|
454
|
+
"rules": [
|
|
455
|
+
{"id": "r1", "action": "proxy", "upstream": "office",
|
|
456
|
+
"targets": "chrome.exe;msedge.exe", "dst_port": "443,80"},
|
|
457
|
+
],
|
|
458
|
+
},
|
|
459
|
+
"upstreams": [
|
|
460
|
+
{"alias": "office", "kind": "socks5", "host": "127.0.0.1", "port": 1080},
|
|
461
|
+
],
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
cfg = Config.from_dict(doc)
|
|
465
|
+
cfg.validate() # from_dict 只解析,不校验
|
|
466
|
+
atomic_write(cfg, "myconfig.yaml") # 临时文件 → 校验 → 原子替换
|
|
467
|
+
|
|
468
|
+
with start_proxy("myconfig.yaml") as ppx:
|
|
469
|
+
...
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
> `Config.from_dict()` 不会解析 `password_ref`;需要凭据时请用
|
|
473
|
+
> `Config.load()` / `start_proxy(path)`,或自己给 `upstream.password` 赋值。
|
|
474
|
+
|
|
475
|
+
### 只做决策,不启动数据面
|
|
476
|
+
|
|
477
|
+
```python
|
|
478
|
+
from proxycore.api import make_runtime
|
|
479
|
+
|
|
480
|
+
runtime = make_runtime() # 默认用内置配置,backend=null
|
|
361
481
|
decision = runtime.decide(conn_request)
|
|
482
|
+
print(decision.action, decision.reason)
|
|
362
483
|
```
|
|
363
484
|
|
|
364
|
-
|
|
485
|
+
### 生命周期与句柄
|
|
486
|
+
|
|
487
|
+
```python
|
|
488
|
+
ppx = start_proxy()
|
|
489
|
+
try:
|
|
490
|
+
print(ppx.status())
|
|
491
|
+
finally:
|
|
492
|
+
ppx.stop() # 幂等;with 退出时也会自动调用
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
| 成员 | 说明 |
|
|
496
|
+
|---|---|
|
|
497
|
+
| `status()` | 后端、规则、会话、熔断、DNS、UDP、sink、`config_path`、`config_source` |
|
|
498
|
+
| `sessions(limit=50)` / `active_sessions()` | 会话明细 / 活跃数 |
|
|
499
|
+
| `reload(path="")` | 热重载;不传路径则重读当前文件。`sink.port`/`backend` 变更需重启 |
|
|
500
|
+
| `decide(conn)` | 只问规则引擎,不抓包、不改道 |
|
|
501
|
+
| `profile` | 当前生效的 `Profile` |
|
|
502
|
+
| `config_path` / `config_source` | 当前配置的绝对路径与来源 |
|
|
503
|
+
| `running` | 是否仍在运行 |
|
|
504
|
+
|
|
505
|
+
`start_proxy()` 会启动后台维护线程;`run_forever()` 会阻塞到 Ctrl+C。
|
|
506
|
+
请在主线程使用,并在退出时 `stop()`(或使用 `with`)。
|
|
507
|
+
|
|
508
|
+
### 错误处理
|
|
509
|
+
|
|
510
|
+
配置 / 后端 / 启动失败统一抛 `ProxyStartError`,`code` 是稳定的机器可读标识:
|
|
511
|
+
|
|
512
|
+
```python
|
|
513
|
+
from proxycore.api import ProxyStartError, start_proxy
|
|
514
|
+
|
|
515
|
+
try:
|
|
516
|
+
start_proxy("missing.yaml")
|
|
517
|
+
except ProxyStartError as exc:
|
|
518
|
+
print(exc.code) # config_not_found
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
| code | 含义 |
|
|
522
|
+
|---|---|
|
|
523
|
+
| `config_not_found` | 配置文件不存在(显式路径 / 环境变量不会回退) |
|
|
524
|
+
| `config_unreadable` | 文件存在但读不了(权限、目录等) |
|
|
525
|
+
| `config_parse_invalid` | YAML 语法错误 / 根节点非映射 / 非 UTF-8 |
|
|
526
|
+
| `config_version_unsupported` | `version != 1` |
|
|
527
|
+
| `rule_upstream_missing` 等 | 规则或上游校验失败(完整列表见文档) |
|
|
528
|
+
| `E_BACKEND_UNAVAILABLE` | 后端不可用(未知后端、WinDivert 不可加载等) |
|
|
529
|
+
|
|
530
|
+
`api.load_config()` 同样抛 `ProxyStartError`,不是 `ConfigError`。
|
|
531
|
+
|
|
532
|
+
### 环境变量
|
|
533
|
+
|
|
534
|
+
| 变量 | 作用 |
|
|
535
|
+
|---|---|
|
|
536
|
+
| `PROCPROXY_CONFIG` | 配置文件路径;显式路径之后、用户配置之前生效 |
|
|
537
|
+
| `PROCPROXY_RUNTIME_DIR` | 运行时状态/日志目录(CLI 与服务使用) |
|
|
538
|
+
|
|
539
|
+
跑 `python tests/tools/api_demo.py` 看完整演示。
|
|
365
540
|
|
|
366
541
|
---
|
|
367
542
|
|
|
@@ -406,12 +581,13 @@ src/proxycore/ 核心包
|
|
|
406
581
|
├── tunnel/ sink + relay(本地落地与双向转发)
|
|
407
582
|
├── upstream/ SOCKS5 / SOCKS4 / HTTP CONNECT / 跳链
|
|
408
583
|
├── dns/ DNS 三模式与 UDP
|
|
584
|
+
├── config_source.py 配置来源解析(显式 / env / 用户 / 样例 / 内置)
|
|
409
585
|
├── forward.py ← procproxy.py <进程名> 的实现
|
|
410
586
|
├── canproxy.py / checkroute.py / probe.py / pathsetup.py ← 其余子命令
|
|
411
587
|
└── service/ ipc.py Windows 服务 + 命名管道
|
|
412
588
|
samples/ mock 服务 + 示例配置
|
|
413
|
-
docs/ 文档(00
|
|
414
|
-
tests/ 测试套件(
|
|
589
|
+
docs/ 文档(00 架构 / 07 规则 / 11 排错 / 14 抓包 / 15 SDK)
|
|
590
|
+
tests/ 测试套件(624 passed / 4 skipped)
|
|
415
591
|
└── tools/ 验证脚本(run_demo / run_e2e / bench / …)
|
|
416
592
|
```
|
|
417
593
|
|
|
@@ -432,7 +608,7 @@ tests/ 测试套件(555 passed)
|
|
|
432
608
|
|
|
433
609
|
## 排错
|
|
434
610
|
|
|
435
|
-
见 [`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)(症状 → 定位 → 解决)。
|
|
436
612
|
|
|
437
613
|
最常见的一条:**`[WinError 5] 拒绝访问` = 不是管理员**。
|
|
438
614
|
|
|
@@ -442,7 +618,7 @@ tests/ 测试套件(555 passed)
|
|
|
442
618
|
|
|
443
619
|
```bash
|
|
444
620
|
pip install -e ".[dev]"
|
|
445
|
-
python -m pytest -q tests/ #
|
|
621
|
+
python -m pytest -q tests/ # 624 passed / 4 skipped(非管理员 Windows)
|
|
446
622
|
python -m ruff check src tests
|
|
447
623
|
python -m mypy src/proxycore
|
|
448
624
|
```
|
|
@@ -35,10 +35,12 @@ 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` 会显示首次使用指引,不依赖任何样例文件。
|
|
42
|
+
Python SDK 也一样:`start_proxy()` 不传配置即可启动(内置 `backend=null`),
|
|
43
|
+
不需要先跑 `init`;`init` 只用于生成可编辑配置。
|
|
42
44
|
|
|
43
45
|
非管理员:WinDivert 抓包必须管理员;可以用 `--backend null` 做转发链路联调,
|
|
44
46
|
或在服务已启动、且配置了 `service.ipc_allow_group` 时读取状态。
|
|
@@ -209,7 +211,7 @@ python procproxy.py Weixin.exe WeChatAppEx.exe --port 8848
|
|
|
209
211
|
⚠️ 只有 ① 没有 ② → 端口填错了(**要填抓包工具的 MITM 监听口,不是它的 Web 管理口**)。
|
|
210
212
|
① ② 都正常但内容看不懂 → 那是 TLS,不是转发的问题。
|
|
211
213
|
|
|
212
|
-
完整指南(含排错与参数表)见 [`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)。
|
|
213
215
|
|
|
214
216
|
---
|
|
215
217
|
|
|
@@ -299,30 +301,203 @@ rules: # 自上而下,**首个命中生
|
|
|
299
301
|
7. 都没命中 → profile.default_action
|
|
300
302
|
```
|
|
301
303
|
|
|
302
|
-
完整语义见 [`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)。
|
|
303
305
|
|
|
304
306
|
---
|
|
305
307
|
|
|
306
308
|
## 编程接口
|
|
307
309
|
|
|
310
|
+
`proxycore.api` 是与 CLI 共用同一套配置、规则引擎和会话表的 SDK。
|
|
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
|
+
|
|
313
|
+
### 30 秒:零配置启动
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
from proxycore.api import start_proxy
|
|
317
|
+
|
|
318
|
+
with start_proxy() as ppx: # 不需要任何配置文件
|
|
319
|
+
print(ppx.config_source) # "packaged"
|
|
320
|
+
print(ppx.config_path) # .../proxycore/data/default.yaml
|
|
321
|
+
print(ppx.status()) # 后端 / 规则 / 会话 / UDP / 配置来源
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
不传配置时的来源优先级:
|
|
325
|
+
|
|
326
|
+
| 优先级 | 来源 | 说明 |
|
|
327
|
+
|---|---|---|
|
|
328
|
+
| 1 | `start_proxy(path)` | 显式路径(也接受内存中的 `Config` 对象) |
|
|
329
|
+
| 2 | `PROCPROXY_CONFIG` | 指向不存在文件会直接报错,不回退 |
|
|
330
|
+
| 3 | `~/.procproxy/config.yaml` | `procproxy init` 生成的用户配置 |
|
|
331
|
+
| 4 | 包内 `data/default.yaml` | `backend=null`,不抓包、不改道 |
|
|
332
|
+
|
|
333
|
+
内置配置**不会**监听 sink,也**不会**创建任何文件。它适合装配、规则决策、
|
|
334
|
+
状态查询和联调;要真实抓包请用 `backend="windivert"`(需管理员)或
|
|
335
|
+
`procproxy init` 生成自己的配置。
|
|
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
|
+
|
|
308
372
|
```python
|
|
309
|
-
from proxycore import
|
|
373
|
+
from proxycore.api import start_proxy
|
|
310
374
|
|
|
311
|
-
#
|
|
312
|
-
|
|
313
|
-
print(
|
|
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)。
|
|
314
382
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
383
|
+
### 显式配置与测试转发
|
|
384
|
+
|
|
385
|
+
```python
|
|
386
|
+
from proxycore.api import start_proxy
|
|
387
|
+
|
|
388
|
+
# 显式路径 + 真实抓包(需要管理员)
|
|
389
|
+
with start_proxy(r"D:\cfg\procproxy.yaml", backend="windivert") as ppx:
|
|
390
|
+
print(ppx.sink) # sink 监听地址
|
|
391
|
+
print(ppx.sessions(limit=20))
|
|
392
|
+
|
|
393
|
+
# 联调模式:backend=null + 把 sink 收到的连接固定转发到目标
|
|
394
|
+
with start_proxy(backend="null", sink_test_target="127.0.0.1:8080",
|
|
395
|
+
upstream="local-mock") as ppx:
|
|
318
396
|
...
|
|
397
|
+
# curl -x http://127.0.0.1:19080 http://any/ → 127.0.0.1:8080
|
|
398
|
+
```
|
|
319
399
|
|
|
320
|
-
|
|
321
|
-
|
|
400
|
+
### 在代码里构建配置
|
|
401
|
+
|
|
402
|
+
可以从字典构造 `Config`,也可以先落盘再按路径加载:
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
from proxycore.config import Config, atomic_write
|
|
406
|
+
from proxycore.api import start_proxy
|
|
407
|
+
|
|
408
|
+
doc = {
|
|
409
|
+
"version": 1,
|
|
410
|
+
"service": {"sink": {"host": "127.0.0.1", "port": 19080}, "backend": "null"},
|
|
411
|
+
"profile": {
|
|
412
|
+
"name": "myapp",
|
|
413
|
+
"default_action": "direct",
|
|
414
|
+
"dns_mode": "remote",
|
|
415
|
+
"rules": [
|
|
416
|
+
{"id": "r1", "action": "proxy", "upstream": "office",
|
|
417
|
+
"targets": "chrome.exe;msedge.exe", "dst_port": "443,80"},
|
|
418
|
+
],
|
|
419
|
+
},
|
|
420
|
+
"upstreams": [
|
|
421
|
+
{"alias": "office", "kind": "socks5", "host": "127.0.0.1", "port": 1080},
|
|
422
|
+
],
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
cfg = Config.from_dict(doc)
|
|
426
|
+
cfg.validate() # from_dict 只解析,不校验
|
|
427
|
+
atomic_write(cfg, "myconfig.yaml") # 临时文件 → 校验 → 原子替换
|
|
428
|
+
|
|
429
|
+
with start_proxy("myconfig.yaml") as ppx:
|
|
430
|
+
...
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
> `Config.from_dict()` 不会解析 `password_ref`;需要凭据时请用
|
|
434
|
+
> `Config.load()` / `start_proxy(path)`,或自己给 `upstream.password` 赋值。
|
|
435
|
+
|
|
436
|
+
### 只做决策,不启动数据面
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
from proxycore.api import make_runtime
|
|
440
|
+
|
|
441
|
+
runtime = make_runtime() # 默认用内置配置,backend=null
|
|
322
442
|
decision = runtime.decide(conn_request)
|
|
443
|
+
print(decision.action, decision.reason)
|
|
323
444
|
```
|
|
324
445
|
|
|
325
|
-
|
|
446
|
+
### 生命周期与句柄
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
ppx = start_proxy()
|
|
450
|
+
try:
|
|
451
|
+
print(ppx.status())
|
|
452
|
+
finally:
|
|
453
|
+
ppx.stop() # 幂等;with 退出时也会自动调用
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
| 成员 | 说明 |
|
|
457
|
+
|---|---|
|
|
458
|
+
| `status()` | 后端、规则、会话、熔断、DNS、UDP、sink、`config_path`、`config_source` |
|
|
459
|
+
| `sessions(limit=50)` / `active_sessions()` | 会话明细 / 活跃数 |
|
|
460
|
+
| `reload(path="")` | 热重载;不传路径则重读当前文件。`sink.port`/`backend` 变更需重启 |
|
|
461
|
+
| `decide(conn)` | 只问规则引擎,不抓包、不改道 |
|
|
462
|
+
| `profile` | 当前生效的 `Profile` |
|
|
463
|
+
| `config_path` / `config_source` | 当前配置的绝对路径与来源 |
|
|
464
|
+
| `running` | 是否仍在运行 |
|
|
465
|
+
|
|
466
|
+
`start_proxy()` 会启动后台维护线程;`run_forever()` 会阻塞到 Ctrl+C。
|
|
467
|
+
请在主线程使用,并在退出时 `stop()`(或使用 `with`)。
|
|
468
|
+
|
|
469
|
+
### 错误处理
|
|
470
|
+
|
|
471
|
+
配置 / 后端 / 启动失败统一抛 `ProxyStartError`,`code` 是稳定的机器可读标识:
|
|
472
|
+
|
|
473
|
+
```python
|
|
474
|
+
from proxycore.api import ProxyStartError, start_proxy
|
|
475
|
+
|
|
476
|
+
try:
|
|
477
|
+
start_proxy("missing.yaml")
|
|
478
|
+
except ProxyStartError as exc:
|
|
479
|
+
print(exc.code) # config_not_found
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
| code | 含义 |
|
|
483
|
+
|---|---|
|
|
484
|
+
| `config_not_found` | 配置文件不存在(显式路径 / 环境变量不会回退) |
|
|
485
|
+
| `config_unreadable` | 文件存在但读不了(权限、目录等) |
|
|
486
|
+
| `config_parse_invalid` | YAML 语法错误 / 根节点非映射 / 非 UTF-8 |
|
|
487
|
+
| `config_version_unsupported` | `version != 1` |
|
|
488
|
+
| `rule_upstream_missing` 等 | 规则或上游校验失败(完整列表见文档) |
|
|
489
|
+
| `E_BACKEND_UNAVAILABLE` | 后端不可用(未知后端、WinDivert 不可加载等) |
|
|
490
|
+
|
|
491
|
+
`api.load_config()` 同样抛 `ProxyStartError`,不是 `ConfigError`。
|
|
492
|
+
|
|
493
|
+
### 环境变量
|
|
494
|
+
|
|
495
|
+
| 变量 | 作用 |
|
|
496
|
+
|---|---|
|
|
497
|
+
| `PROCPROXY_CONFIG` | 配置文件路径;显式路径之后、用户配置之前生效 |
|
|
498
|
+
| `PROCPROXY_RUNTIME_DIR` | 运行时状态/日志目录(CLI 与服务使用) |
|
|
499
|
+
|
|
500
|
+
跑 `python tests/tools/api_demo.py` 看完整演示。
|
|
326
501
|
|
|
327
502
|
---
|
|
328
503
|
|
|
@@ -367,12 +542,13 @@ src/proxycore/ 核心包
|
|
|
367
542
|
├── tunnel/ sink + relay(本地落地与双向转发)
|
|
368
543
|
├── upstream/ SOCKS5 / SOCKS4 / HTTP CONNECT / 跳链
|
|
369
544
|
├── dns/ DNS 三模式与 UDP
|
|
545
|
+
├── config_source.py 配置来源解析(显式 / env / 用户 / 样例 / 内置)
|
|
370
546
|
├── forward.py ← procproxy.py <进程名> 的实现
|
|
371
547
|
├── canproxy.py / checkroute.py / probe.py / pathsetup.py ← 其余子命令
|
|
372
548
|
└── service/ ipc.py Windows 服务 + 命名管道
|
|
373
549
|
samples/ mock 服务 + 示例配置
|
|
374
|
-
docs/ 文档(00
|
|
375
|
-
tests/ 测试套件(
|
|
550
|
+
docs/ 文档(00 架构 / 07 规则 / 11 排错 / 14 抓包 / 15 SDK)
|
|
551
|
+
tests/ 测试套件(624 passed / 4 skipped)
|
|
376
552
|
└── tools/ 验证脚本(run_demo / run_e2e / bench / …)
|
|
377
553
|
```
|
|
378
554
|
|
|
@@ -393,7 +569,7 @@ tests/ 测试套件(555 passed)
|
|
|
393
569
|
|
|
394
570
|
## 排错
|
|
395
571
|
|
|
396
|
-
见 [`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)(症状 → 定位 → 解决)。
|
|
397
573
|
|
|
398
574
|
最常见的一条:**`[WinError 5] 拒绝访问` = 不是管理员**。
|
|
399
575
|
|
|
@@ -403,7 +579,7 @@ tests/ 测试套件(555 passed)
|
|
|
403
579
|
|
|
404
580
|
```bash
|
|
405
581
|
pip install -e ".[dev]"
|
|
406
|
-
python -m pytest -q tests/ #
|
|
582
|
+
python -m pytest -q tests/ # 624 passed / 4 skipped(非管理员 Windows)
|
|
407
583
|
python -m ruff check src tests
|
|
408
584
|
python -m mypy src/proxycore
|
|
409
585
|
```
|