Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Podman 5.0 的破坏性更新使得 Rootless 模式下 socks5 服务器无法正常收到任何请求 #339

Closed
w568w opened this issue Mar 25, 2024 · 9 comments · Fixed by #351
Labels
bug Something isn't working enhancement New feature or request good first issue Good for newcomers

Comments

@w568w
Copy link

w568w commented Mar 25, 2024

问题

Podman 升级到 5.0 之后,Rootless 模式下运行本项目的 cli 版本,http 代理正常,但 socks5 代理无法连接。实际上,socks5 代理看起来没有收到任何请求。


Podman 5.0 更新公告 中,提到:

Pasta is now the default rootless networking backend, offering greatly improved performance for rootless Podman.

原先的默认网络后端是 slirp4netns,而 5.0 中变更为 pasta。

这两者的行为很不一致,例如前者会创建名为 tap0 的虚拟接口,后者则会将宿主机的网络接口名映射到内部。

start.sh 从几个端口中猜测内部接口名($internals):

internals=""
externals=""
for iface in $(ip -o addr | sed -E 's/^[0-9]+: ([^ ]+) .*/\1/' | sort | uniq | grep -v "lo\|sit\|vir"); do
internals="${internals}internal: $iface port = 1080\\n"
externals="${externals}external: $iface\\n"
done
externals="${externals}external: $VPN_TUN\\n"
sed /^internal:/c"$internals" -i /run/danted.conf
sed /^external:/c"$externals" -i /run/danted.conf

在我的设备上,slirp4netns 模式下获得的接口名是 tap0,而 pasta 下是 wlps0(和主机网络接口名相同)。

该脚本将该接口名传递给 dante 程序,使之仅监听 $internals 接口。然而,在 pasta 模式下,监听 wlps0 将不会收到任何请求。具体原因还需查明,但我猜测 pasta 仅会转发去往 localhost 的请求(即 lo 接口),或者是由于网络接口名变化,脚本中某些地方的防火墙配置出现了问题。

另一方面,http 代理可以正常工作。我猜想这是因为它监听了所有网络接口。

太长不看:一个简单粗暴的解决方案是要求创建容器时添加 --network slirp4netns,从而设置网络模式为原先的模式。


相关信息

系统:Archlinux x86_64

Podman 版本:5.0.0

启动参数(请以普通用户身份执行以复现该 bug,不要用 root 或 sudo):

/usr/bin/podman run \
	--rm \
	--replace \
	-d \
	--device /dev/net/tun \
	--cap-add NET_ADMIN \
	-ti \
	-p 127.0.0.1:1080:1080 \
	-p 127.0.0.1:8888:8888 \
	-e EC_VER=7.6.7 \
	-e "CLI_OPTS=-d stuvpn.fudan.edu.cn:443 -u abc -p def" \
	--name ecvpn docker.io/hagb/docker-easyconnect:cli

容器内执行 ip addr,pasta 模式下(socks5 异常):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: wlp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether 76:0e:02:e2:32:a5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.155/24 brd 192.168.1.255 scope global noprefixroute wlp4s0
       valid_lft forever preferred_lft forever
    inet6 fe80::740e:2ff:fee2:32a5/64 scope link 
       valid_lft forever preferred_lft forever
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 10.230.32.69/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::c403:bf9:99fb:798c/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever

容器内执行 ip addr,slirp4netns 模式下(socks5 正常):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: tap0: <BROADCAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether fe:05:e9:db:f8:d0 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.100/24 brd 10.0.2.255 scope global tap0
       valid_lft forever preferred_lft forever
    inet6 fd00::fc05:e9ff:fedb:f8d0/64 scope global dynamic mngtmpaddr 
       valid_lft 86324sec preferred_lft 14324sec
    inet6 fe80::fc05:e9ff:fedb:f8d0/64 scope link 
       valid_lft forever preferred_lft forever
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 10.230.32.2/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::8854:65e9:2562:8ba9/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever

容器内执行 cat /run/danted.conf,slirp4netns 模式下(socks5 正常):

#logging
errorlog: /dev/stderr
#logoutput: /var/log/sockd.log
#debug: 2

#server address specification
internal: tap0 port = 1080

external: tap0
external: tun0

external.rotation: route

#server identities (not needed on solaris)
user.privileged: root
user.notprivileged: socks
#user.libwrap: libwrap

#authentication methods
clientmethod: none
socksmethod: none

##
## SOCKS client access rules
##
#rule processing stops at the first match, no match results in blocking

#block access to socks server from 192.0.2.22 (exception for pass rule below)
# client block {
#       #block connections from 192.0.2.22/32
#       from: 192.0.2.22/24 to: 0.0.0.0/0
#       log: error # connect disconnect
# }

#allow all connections
client pass {
        from: 0/0 to: 0/0
        log: error # connect disconnect
}

##
## SOCKS command rules
##
#rule processing stops at the first match, no match results in blocking

#block communication with www.example.org
# socks block {
#        from: 0.0.0.0/0 to: www.example.org
#        command: bind connect udpassociate
#        log: error # connect disconnect iooperation
# }

#generic pass statement - bind/outgoing traffic
socks pass {
        from: 0/0 to: 0/0
        command: bind connect udpassociate
        log: error # connect disconnect iooperation
}

#block incoming connections/packets from ftp.example.org
# socks block {
#        from: ftp.example.org to: 0.0.0.0/0
#        command: bindreply udpreply
#        log: error # connect disconnect iooperation
# }

#generic pass statement for incoming connections/packets
socks pass {
        from: 0/0 to: 0/0
        command: bindreply udpreply
        log: error # connect disconnect iooperation
}

容器内执行 cat /run/danted.conf,pasta 模式下和上面唯一的区别是 internal: tap0 port = 1080 变成了 internal: wlp4s0 port = 1080

@enoch-robinson
Copy link

我在基于WSL2的podman 5.0中使用rootless模式启动容器,尝试socks连接时使用wsl虚拟机的ip可以成功连上。
在容器内使用ss -tlnp |grep 1080 观察到容器内监听的是虚拟机ip

@Hagb Hagb added good first issue Good for newcomers bug Something isn't working enhancement New feature or request labels May 6, 2024
@Hagb
Copy link
Collaborator

Hagb commented May 6, 2024

感谢两位的反馈!我测试了一下,看起来 Pasta 的默认行为是:从宿主机的哪个网络接口入站的,在容器里面也在同一接口入站。这也可以解释为什么从外部可以访问到,而直接在宿主机访问 127.0.0.1 却不行: danted 没有监听 lo。
于是在 danted.conf 里加入 internal: lo port = 1080 或者把 52 行处的 grep -v "lo\|sit\|vir" 改为 grep -v "sit\|vir" 应该可以解决。

internals=""
externals=""
for iface in $(ip -o addr | sed -E 's/^[0-9]+: ([^ ]+) .*/\1/' | sort | uniq | grep -v "lo\|sit\|vir"); do
internals="${internals}internal: $iface port = 1080\\n"
externals="${externals}external: $iface\\n"
done
externals="${externals}external: $VPN_TUN\\n"
sed /^internal:/c"$internals" -i /run/danted.conf
sed /^external:/c"$externals" -i /run/danted.conf

我得询问这部分的贡献者有没有这样做(排除 lo)的特别的原因再去修改。

@redjumper
Copy link
Contributor

在容器内部,slirp4netns使用tap0与宿主机通信,pasta直接使用宿主机的接口。
slirp4netns模式下,即使容器只对127.0.0.1暴露端口,容器内部也必须要监听tap0,不然本机一样无法访问到容器内部的namespace。pasta模式不一样,它直接使用宿主机的接口,在只对127.0.0.1暴露端口时,容器内部只用监听lo就行。

@redjumper
Copy link
Contributor

@w568w 能否帮忙测试下,internal直接监听0.0.0.0

具体步骤如下

容器内执行

busybox vi /run/danted.conf

修改danted.conf,删除原先internal开头的行,改成

internal: 0.0.0.0 port = 1080
internal: :: port = 1080

busybox ps -ef

查找包含 /usr/sbin/danted -D -f /run/danted.conf的行,类似

118 socks /usr/sbin/danted -D -f /run/danted.conf

kill -9 pid  #替换pid为上面找到的值,比如118
/usr/sbin/danted -D -f /run/danted.conf

@w568w
Copy link
Author

w568w commented May 15, 2024

能否帮忙测试下,internal 直接监听 0.0.0.0

已经测试,pasta 模式下按此操作后可以正常通过 socks5 代理访问网站。

@redjumper
Copy link
Contributor

@w568w 测试时代理是全局的吗。还有个点忘记让你帮忙测试了。全局代理的情况下,访问百度之类的网站是否正常

@w568w
Copy link
Author

w568w commented May 21, 2024

测试时代理是全局的吗

我直接用 Curl 测试的。

访问百度之类的网站是否正常

都是正常的:

$ curl -skx socks://127.0.0.1:1080 https://<学校内网 IP> | tail -n 10
  </div>

  <script type="text/javascript">
    /* Hide everything classed as "noscript" */
    document.querySelectorAll('.noscript').forEach(function(element){
      element.hidden = true;
    });
  </script>
</body>
</html>

$ curl -skx socks://127.0.0.1:1080 https://baidu.com | tail -n 10
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>bfe/1.0.8.18</center>
</body>
</html>

@redjumper
Copy link
Contributor

redjumper commented May 21, 2024 via email

redjumper added a commit to redjumper/docker-easyconnect that referenced this issue May 21, 2024
@Hagb Hagb closed this as completed in #351 May 21, 2024
@Hagb
Copy link
Collaborator

Hagb commented May 22, 2024

@w568w 感谢反馈。可以试一下重新 podman pull docker.io/hagb/docker-easyconnect:cli 然后运行看看是否解决问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants
@w568w @Hagb @redjumper @enoch-robinson and others