Skip to content

chenjia404/meshproxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

274 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

meshproxy

meshproxy 是一个使用 Go 编写的“去中心化匿名代理网络 + 本地 SOCKS5 Agent + 匿名聊天”原型实现,目前处于早期 MVP 阶段。

安卓客户端 https://github.com/chenjia404/meshproxy-android

架构与模块

  • cmd/node/main.go:节点主程序入口,负责读取配置、初始化 App 并处理信号退出。
  • internal/app:聚合配置、身份、P2P、发现、Circuit、SOCKS5、本地 API 等组件的主应用层。
  • internal/config:YAML 配置加载、默认值与校验,支持 relay / relay+exit 两种模式。
  • internal/identity:Ed25519 私钥生成与持久化,供 libp2p host 使用。
  • internal/p2p:libp2p host、DHT、Gossip、bootstrap 以及协议 ID 定义。
  • internal/discovery:节点 descriptor 定义、签名验签、gossip 广播与缓存管理。
  • internal/protocol:电路协议常量、结构与统一 frame 编码(CREATE/EXTEND/BEGIN_TCP/DATA/END 等),以及多跳分层加密(X25519 + AEAD 洋葱封装)。
  • internal/client:本地 SOCKS5、路径选择器(PathSelector)、CircuitManager、StreamManager。
  • internal/relay / internal/exit:relay / exit 服务实现,relay 仅解一层洋葱并转发,exit 解最后一层并连接目标 TCP。
  • internal/api:本地管理 HTTP API 与内嵌 Web 控制台(/console/),提供节点状态、已知节点、电路、stream、错误与指标等信息。
  • meshserver-api.md:meshserver 中心化群的本地 API 说明,包含连接、服务器、频道、消息和同步接口示例。
  • internal/store:内存 KV store 与 circuit store。
  • proto/meshproxy.proto:后续用于生成 Protobuf 类型。
  • configs/config.example.yaml:示例配置。

界面截图

控制台:http://127.0.0.1:19080/console

控制台

去中心化加密聊天:http://127.0.0.1:19080/chat

去中心化加密聊天

群聊: 群聊 加密聊天简介

meshproxy 现在内置了一套点对点加密聊天原型页面,入口为 http://127.0.0.1:19080/chat。这套聊天能力不是独立再造一张网络,而是直接复用当前 meshproxy 已有的去中心化网络底座:

  • 使用现有 libp2p Peer ID 作为设备身份
  • 优先尝试 direct stream 直连通信
  • 直连失败时自动回退到 relay-e2e 中继转发
  • 中间 relay 只负责转发,聊天内容仍然保持应用层端到端加密
  • 聊天数据本地持久化到 data/chat.db

当前聊天页支持:

  • 修改本机昵称
  • 发起聊天请求、接受/拒绝请求
  • 联系人备注名与拉黑
  • 单聊文本消息发送
  • delivery_ack 已送达确认
  • 单条消息撤回(双端删除,本地数据库也会删除)
  • 会话级自动删除时间设置,并同步到对端

当前实现边界:

  • 单聊文本为主,暂未实现群聊、文件传输和语音媒体流
  • 聊天优先依赖当前节点发现能力;如果部署环境禁用了 nodisc,则主要依赖 bootstrap + gossip + peer exchange
  • 对端完全不可达时,像撤回、自动删除同步这类需要双端一致的操作会返回失败,而不会只改本地

编译与运行

go mod tidy
go build -o bin/meshproxy ./cmd/node
./bin/meshproxy -config configs/config.example.yaml

启动后可通过 Web 控制台本地 API 管理与查询状态(API 默认 http://127.0.0.1:19080):

  • Web 控制台:在浏览器打开 http://127.0.0.1:19080/console/,可查看节点状态、已知 Relay/Exit、Circuit/Stream 列表、实时流量汇总、日志面板等,无需直接查看 JSON API。

  • GET /api/v1/status:节点状态(peer_id, mode, socks5_listen, p2p_listen_addrs, uptime_seconds, relays_known, exits_known, circuit_pool)。

  • GET /api/v1/nodes:已知节点 descriptor 缓存。

  • GET /api/v1/relays:已知 relay 节点列表。

  • GET /api/v1/exits:已知 exit 节点列表。

  • GET /api/v1/circuits:当前电路列表(含每条电路路径 planrelay_peer_idexit_peer_idhop_countstream_countcreated_atupdated_at)。

  • GET /api/v1/streams:当前 stream 列表(含目标与状态,以及对应电路的 relay_peer_idexit_peer_idhop_count)。

  • GET /api/v1/scores:peer 评分(预留,目前返回空)。

  • GET /api/v1/errors/recent:最近错误记录。

  • GET /api/v1/metrics/summary:汇总指标(circuits_total, streams_active, relays_known, exits_known, errors_recent_count, pool_status 等)。

出口节点专用 API(仅在 mode: relay+exit 时可用)

  • GET /api/v1/exit/policy:当前出口策略与运行时配置。
  • POST /api/v1/exit/policy:更新策略或运行时(请求体可含 policy / runtime,仅更新内存,重启后以配置文件为准)。
  • GET /api/v1/exit/status:运行状态(drain_mode、accept_new_streams、open_connections、recent_rejects)。
  • POST /api/v1/exit/drain:进入维护模式(不再接受新 stream)。
  • POST /api/v1/exit/resume:结束维护模式。

Android 编译(生成可在安卓上运行的二进制文件)

在 Windows PowerShell 下,将 ./cmd/node 编译为 Android arm64 二进制文件的示例命令为:

$env:GOOS="android"; $env:GOARCH="arm64"; $env:CGO_ENABLED="0"; go build -trimpath -buildvcs=false -o bin/meshproxy.so -ldflags="-w -s" -ldflags "-checklinkname=0" ./cmd/node

配置说明

示例配置位于 configs/config.example.yaml,主要字段:

  • moderelayrelay+exit
    • relay:仅作为中继节点,不直接作为出口。
    • relay+exit:同时具备 relay 与 exit 能力。
  • data_dir:用于存放身份密钥等持久化数据。
  • identity_key_path:如为空,默认值为 ${data_dir}/identity.key
  • p2p.listen_addrs:libp2p 监听 multiaddr 列表,例如 "/ip4/0.0.0.0/tcp/0"
  • p2p.public_ip:手动指定对外广播的公网 IP。设置后,libp2p 会把监听地址里的内网/任意地址改写成这个公网 IP,并关闭 identify 地址发现,避免广播大量内网地址。
  • p2p.bootstrap_peers:其他节点的 multiaddr,用于启动时连接引导。
  • p2p.nodisc:是否禁用 DHT 节点发现。为 true 时不会执行 rendezvous Advertise/FindPeers,只依赖 bootstrap_peers、已连接节点的 gossip descriptor 与 peer exchange。
  • socks5.listen:本地 SOCKS5 监听地址,例如 127.0.0.1:1080
  • socks5.allow_udp_associate:是否啟用 SOCKS5 UDP ASSOCIATE(預設 false);啟用後需出口策略 exit.policy.allow_udp: true 配合。
  • socks5.tunnel_to_exit:是否开启“本地原样转发到 exit 的 SOCKS5”模式。开启后,本地 socks5.listen 接收到的 TCP 连接不会在本地解析 SOCKS5,而是直接通过 raw libp2p stream 原样转发到 exit 节点上的 SOCKS5 服务。
  • socks5.exit_upstream:当 socks5.tunnel_to_exit: true 时,exit 节点实际连接的上游 SOCKS5 地址,默认 127.0.0.1:1081relay+exit 节点会额外启动一个标准 SOCKS5(默认 1081),它直接出网,但仍受出口策略限制。
  • api.listen:本地 HTTP API 监听地址,例如 127.0.0.1:19080
  • log_modules:逗号分隔的模块名,用于过滤标准库 log 输出:只保留消息中带 [模块名] 标签的行(例如配置 chat 对应代码里的 log.Printf("[chat] ..."));留空则不过滤、输出全部。不带 [xxx] 前缀的行(如启动提示)仍会输出。也可通过命令行 --log_modules=chat,path_selector 覆盖配置文件。

出口策略(仅在 mode: relay+exit 时生效):在配置中可加入 exit 段,用于控制出口允许的端口、域名、peer、是否允许私网/回环目标,以及维护模式(drain_mode)。默认配置较为保守:仅允许 TCP、80/443,禁止私网与回环。详见 configs/config.example.yaml 中的注释示例。

出口國家解析(GeoIP):當出口節點的 descriptor 未提供 exit_info.country 時,可通過 client.geoip 啟用「從出口節點 IP 推斷國家」:從節點 listen_addrs 中取首個公網 IP,再經 GeoIP 查詢得到國家代碼,用於 country_only / country_preferred 篩選以及 API /api/v1/client/exit-candidatescountry 欄位。

  • client.geoip.provider: ip-api:使用免費服務 ip-api.com(約 45 次/分鐘,建議設 cache_ttl_minutes)。
  • client.geoip.provider: geolite2:使用本地 GeoLite2-Country.mmdb(github.com/oschwald/geoip2-golang/v2);數據庫放在 data_dir 下,若不存在則自動從 P3TERX/GeoLite.mmdb 下載。

日志

项目中有两类日志能力,可并存使用:

  1. 标准库 log(默认)
    业务代码普遍使用 log.Printf("[模块名] ...") 输出。根配置项 log_modules(或命令行 --log_modules)按模块名过滤:多个模块用英文逗号分隔,大小写不敏感;仅当一行日志中第一个符合 [a-zA-Z0-9_-]+ 形式的 [标签] 与列表中某项匹配时才输出该行。
    实现位于 internal/logfilter,在 cmd/node/main.go 校验配置后调用 logfilter.Apply 挂到 log 的输出上。

  2. 结构化日志 internal/meshlog(可选,供新代码逐步采用)
    API 风格参考 go-ethereum/log:基于 log/slog,提供 meshlog.SetDefaultmeshlog.New("module", "chat")、分级 Info/Warn/… 等。默认根 logger 为 丢弃(与 geth 类似),需自行 SetDefault(meshlog.NewLogger(meshlog.StderrTextHandler(meshlog.LevelInfo))) 后才有输出;与现有 log.Printf 互不替换,可并行迁移。

示例:

# 仅看 [chat] 与 [path_selector] 相关标准库日志
./bin/meshproxy --log_modules=chat,path_selector -config configs/config.example.yaml
// 可选:在进程早期配置 meshlog(示例)
meshlog.SetDefault(meshlog.NewLogger(meshlog.StderrTextHandler(meshlog.LevelInfo)))
l := meshlog.New("module", "chat")
l.Info("offline ok", "peer", peerID, "seq", seq)

双节点测试(示意)

假设有两个节点:

  • 节点 Amode: relay+exit,同时作为 relay 与出口。
  • 节点 Bmode: relay,仅作为中继,浏览器连接到 B 的本地 SOCKS5。

基本步骤:

  1. 在节点 A 上启动 meshproxy,记录其 PeerId 与实际 p2p_listen_addrs
  2. 在节点 B 的 configs/config.example.yaml 中,将 A 的 multiaddr 写入 p2p.bootstrap_peers
  3. 如果希望节点 B 不在本地解析 SOCKS5,而是把原始 SOCKS5 流量直接转发给节点 A 的本地 SOCKS5,可在节点 B 配置:
socks5:
  listen: "127.0.0.1:1080"
  tunnel_to_exit: true
  exit_upstream: "127.0.0.1:1081"
  1. 在节点 B 上启动 meshproxy。
  2. 使用浏览器将 HTTP/HTTPS 代理设置为 B 的 SOCKS5 地址(默认 127.0.0.1:1080)。
  3. 尝试访问网站,并通过两端日志及后续的 circuits / streams 查询电路路径。

说明:

  • tunnel_to_exit: true 只建议在客户端节点开启;exit 节点自身通常应保持关闭。
  • exit_upstream 是 exit 端真正处理 SOCKS5 的监听地址;默认就是 exit 节点本机新增的 127.0.0.1:1081

浏览器 SOCKS5 配置提示

  • 浏览器需设置为 SOCKS5 代理,指向本地节点的 socks5.listen
  • 建议关闭浏览器自带 DNS 缓存或启用“通过 SOCKS 解析 DNS”选项,确保域名解析委托给 exit 节点(remote DNS)。

本地 API 示例

  • 节点状态(含 relay/exit 数量与电路池)curl http://127.0.0.1:19080/api/v1/status | jq .
  • 已知节点curl http://127.0.0.1:19080/api/v1/nodes | jq .
  • 已知 relay / exitcurl http://127.0.0.1:19080/api/v1/relays | jq .curl http://127.0.0.1:19080/api/v1/exits | jq .
  • 电路列表(含路径)curl http://127.0.0.1:19080/api/v1/circuits | jq .
  • Stream 列表(目标与状态)curl http://127.0.0.1:19080/api/v1/streams | jq .
  • 最近错误curl http://127.0.0.1:19080/api/v1/errors/recent | jq .
  • 汇总指标curl http://127.0.0.1:19080/api/v1/metrics/summary | jq .

后续演进方向

  • 补全 SOCKS5 协议状态机与流量转发。
  • 基于 libp2p stream 建立 relay / relay+exit 数据通道。
  • 利用 DHT/Gossip 做节点发现、路由公告与健康检查。
  • 扩展本地 API,支持连接状态、路由表与 debug 信息查询。

已知限制

  • 目前支持 TCP 與 UDP:TCP 經 SOCKS5 CONNECT;UDP 經 SOCKS5 UDP ASSOCIATE(需 socks5.allow_udp_associate: true 且出口策略 exit.policy.allow_udp: true)。
  • 尚未支持 DNS over circuit 等进阶功能。
  • DHT / Gossip 仅用于最小节点 descriptor 发现与缓存,尚未设计完整路由/信誉机制。
  • Circuit / Stream 管理仍为内存内部状态,尚未考虑持久化与全网健康度评估。

About

去中心化代理和聊天协议

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages