#wireguard #nat #tcp-udp #incoming-connection #slirp #udp-socket #onetun

libwgslirpy

用户空间的Wireguard到互联网路由器,类似于SLiRP,但使用Wireguard而不是PPP(CLI工具的库部分)

1个不稳定版本

0.2.0 2023年8月13日

#5 in #incoming-connection


用于 wgslirpy

MIT/Apache

57KB
1.5K SLoC

wgslirpy

一个命令行工具(以及一个Rust库),用于在Wireguard链路中接受传入的连接,并使用操作系统常用的套接字API将它们路由到外部网络。
这允许创建一种无需root访问的VPN服务器,例如从Android应用程序或在使用非特权容器时。

Diagram depicting operation of Wgslirpy

功能

  • 使用Boringtun库与一个对等点保持Wireguard连接。
  • 使用smoltcp库解码传入的TCP或UDP连接
  • 将Wireguard从外部世界转发TCP和UDP连接,交换用户空间和真实套接字之间的流量。
  • 对于UDP,孔洞穿透/NAT穿越应该可以工作(尚未测试)
  • 对于TCP,半关闭连接和背压应该可以工作
  • 粗略的DNS服务器,用于使用主机的名称解析机制解析IPv4和IPv6地址。
  • 反向模式用于特定的TCP和UDP端口 - 从主机到Wireguard的连接转发。

限制

  • 没有ICMP(除了针对特定地址的ping测试)。这会影响UDP的“端口不可达”。

演示会话

设置
peer# wg genkey
4Khaa5tgPI9NJsO2R896Yd6748k9fW4aapGZnIcUM14=
peer# wg pubkey <<< 4Khaa5tgPI9NJsO2R896Yd6748k9fW4aapGZnIcUM14=
rPpCjWzIv/yAtZZi+C/pVprie8D0QaGlPtJXlDi6bmI=

gateway$ wg genkey
SG43Zi0wGp4emfJ/XpTnnmtnK8SSjjIHOc3Zh37c928=
gateway$ wg pubkey <<< SG43Zi0wGp4emfJ/XpTnnmtnK8SSjjIHOc3Zh37c928=
MR2RF5Tp+6BKt9k+deKg1GqR3re3ckJKti+uwZA84DU=

peer# ip link add wgslirpyspeer type wireguard
peer# wg set wgslirpyspeer listen-port 9796 private-key <(echo 4Khaa5tgPI9NJsO2R896Yd6748k9fW4aapGZnIcUM14=) peer MR2RF5Tp+6BKt9k+deKg1GqR3re3ckJKti+uwZA84DU= allowed-ips 0.0.0.0/0,::/0
peer# ip netns add testing-wgslirp
peer# ip link set wgslirpyspeer netns testing-wgslirp
peer# ip netns exec testing-wgslirp ip link set wgslirpyspeer up
peer# ip netns exec testing-wgslirp ip addr add 192.168.76.1/32 dev wgslirpyspeer
peer# ip netns exec testing-wgslirp ip addr add fc00::01/128 dev wgslirpyspeer
peer# ip netns exec testing-wgslirp route -4 add default dev wgslirpyspeer
peer# ip netns exec testing-wgslirp route -6 add default dev wgslirpyspeer
peer# mkdir -p /etc/netns/testing-wgslirp
peer# echo nameserver 192.168.72.2 > /etc/netns/testing-wgslirp/resolv.conf
激活
gateway$ RUST_LOG=debug wgslirpy --private-key SG43Zi0wGp4emfJ/XpTnnmtnK8SSjjIHOc3Zh37c928= -b 127.0.0.1:9797 --peer-key rPpCjWzIv/yAtZZi+C/pVprie8D0QaGlPtJXlDi6bmI= --peer-endpoint 127.0.0.1:9796 --keepalive-interval 10 --dns 192.168.72.2:53 --pingable 192.168.72.2
DEBUG boringtun::noise: Sending handshake_initiation
DEBUG boringtun::noise: Received handshake_response local_idx=1 remote_idx=2743606023
DEBUG boringtun::noise: New session session=1
DEBUG boringtun::noise: Sending keepalive

peer# ip netns exec testing-wgslirp wg
interface: wgslirpyspeer
  public key: rPpCjWzIv/yAtZZi+C/pVprie8D0QaGlPtJXlDi6bmI=
  private key: (hidden)
  listening port: 9796

peer: MR2RF5Tp+6BKt9k+deKg1GqR3re3ckJKti+uwZA84DU=
  endpoint: 127.0.0.1:9797
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 46 seconds ago
  transfer: 340 B received, 92 B sent
测试
peer# # ip netns exec testing-wgslirp ping -c 2 192.168.72.2
64 bytes from 192.168.72.2: icmp_seq=1 ttl=64 time=0.705 ms
64 bytes from 192.168.72.2: icmp_seq=2 ttl=64 time=0.435 ms

gateway$ 
INFO wgslirpy::router: New NAT entry for Pingable
DEBUG wgslirpy::router: Finished serving Pingable

peer# ip netns exec testing-wgslirp curl http://example.com/
<!doctype html>
...
</html>

gateway$
DEBUG wgslirpy::router::serve_dns: DNS query example.com:0
DEBUG wgslirpy::router: Sending DNS reply

INFO wgslirpy::router: New NAT entry for Tcp { client_side: Endpoint { addr: Ipv4(Address([192, 168, 76, 1])), port: 48004 }, external_side: Endpoint { addr: Ipv4(Address([93, 184, 216, 34])), port: 80 } }
DEBUG wgslirpy::router::serve_tcp: Connected to upstream TCP
DEBUG wgslirpy::router::serve_tcp: Accepted the connection
DEBUG wgslirpy::router::serve_tcp: EOF received from client
DEBUG wgslirpy::router::serve_tcp: Shutdown finished
DEBUG wgslirpy::router::serve_tcp: EOF
DEBUG wgslirpy::router::serve_tcp: Client TCP socket no longer active
DEBUG boringtun::noise::timers: KEEPALIVE(PERSISTENT_KEEPALIVE)
DEBUG wgslirpy::router: Finished serving Tcp { client_side: Endpoint { addr: Ipv4(Address([192, 168, 76, 1])), port: 48004 }, external_side: Endpoint { addr: Ipv4(Address([93, 184, 216, 34])), port: 80 } }

peer# ip netns exec testing-wgslirp dig +short github.com @8.8.8.8
140.82.112.3

gateway$
01:26:14 INFO wgslirpy::router: New NAT entry for Udp
...
01:27:46 DEBUG wgslirpy::router::serve_udp: Timed out a UDP connection

安装

GitHub发布下载预构建的可执行文件或使用以下命令从源代码安装:cargo install --path .cargo install wgslirpy

CLI选项

wgslirpy --help 输出
Usage: wgslirpy [-k <private-key>] [-f <private-key-file>] -K <peer-key> [-p <peer-endpoint>] [-a <keepalive-interval>] -b <bind-ip-port> [-D <dns>] [-P <pingable>] [--mtu <mtu>] [--tcp-buffer-size <tcp-buffer-size>] [--transmit-queue-capacity <transmit-queue-capacity>] [-u <incoming-udp...>] [-t <incoming-tcp...>]

Expose internet access without root using Wireguard

Options:
  -k, --private-key main private key of this Wireguard node, base64-encoded
  -f, --private-key-file
                    main private key of this Wireguard node (content of a
                    specified file), base64-encoded
  -K, --peer-key    peer's public key
  -p, --peer-endpoint
                    address of the peer's UDP socket, where to send keepalives
  -a, --keepalive-interval
                    keepalive interval, in seconds
  -b, --bind-ip-port
                    where to bind our own UDP socket for Wireguard connection
  -D, --dns         use this UDP socket address as a simple A/AAAA-only DNS
                    server within Wireguard network
  -P, --pingable    reply to ICMP pings on this single address within Wireguard
                    network
  --mtu             maximum transfer unit to use for TCP. Default is 1420.
  --tcp-buffer-size in-application socket TCP buffer size. Note that operating
                    system socket buffer also applies.
  --transmit-queue-capacity
                    nubmer of outgoing (to wireguard) packets to hold in a queue
  -u, --incoming-udp
                    forward this host UDP port into Wireguard network. You need
                    to specify triplet of socket addresses: host, source
                    (optional) and dest. Host address is address to bind
                    operating system socket to. source and dest addreses are
                    used within Wireguard network. Example: -u
                    0.0.0.0:1234,10.0.2.1:1234,10.0.2.15:1234
  -t, --incoming-tcp
                    forward this host TCP port into Wireguard network. You need
                    to specify triplet of socket addresses: host, source
                    (optional) and dest. Host address is address to bind
                    operating system socket to. source and dest addreses are
                    used within Wireguard network. If source port is 0,
                    roundrobin is used. Example: -t 0.0.0.0:1234,,10.0.2.15:1234
  --help            display usage information

Wireguardless (GUE/FOU)模式

您可以使用特殊关键字INSECUREGUE作为本地和节点密钥分别退出Wireguard层。这样,wgslirpy将仅直接作为UDP数据报发送IPv4/IPv6数据包。

示例会话
gateway$ wgslirpy -k INSECURE -K GUE -b 127.0.0.1:6556 --dns 10.0.2.1:53 -P 10.0.2.1
peer# ip fou add port 6555 gue local 127.0.0.1 peer 127.0.0.1 peer_port 6556 dev lo
peer# ip link add guegue type sit remote 127.0.0.1 local 127.0.0.1 encap gue encap-sport 6555 encap-dport 6556 encap-csum
peer# ip link set guegue netns testing-wgslirp
peer# ip netns exec testing-wgslirp ip link set guegue up
peer# ip netns exec testing-wgslirp ip addr add 10.0.2.15/24 dev guegue
peer# ip netns exec testing-wgslirp ip route add default dev guegue
peer# ip netns exec testing-wgslirp ping 10.0.2.1
64 bytes from 10.0.2.1: icmp_seq=4 ttl=64 time=2.53 ms
...

您还可以使用更简单的模式,使用ipipfou代替sitgue,但这将不支持IPv6。

另请参阅

  • onetun - 类似的概念,但设计用于将连接转发到Wireguard而不是从Wireguard转发。
  • SLiRP - 类似的概念,但使用PPP(基于流的连接)而不是基于数据包的Wireguard。

lib.rs:

wgslirpy 库部分 - 基于 Tokio、smoltcp 和 boringtun 的用户空间路由器。有关详细信息,请参阅主文档(即 CLI 工具)。

依赖项

~17–30MB
~546K SLoC