Python 在OpenVPN客户端运行时将套接字绑定到本地IP地址块
我已将我的计算机设置为运行VPN客户端,并希望通过VPN隧道或通过指定套接字上的绑定地址直接通过本地接口连接到internet上的主机。考虑下面的代码示例:Python 在OpenVPN客户端运行时将套接字绑定到本地IP地址块,python,linux,sockets,networking,openvpn,Python,Linux,Sockets,Networking,Openvpn,我已将我的计算机设置为运行VPN客户端,并希望通过VPN隧道或通过指定套接字上的绑定地址直接通过本地接口连接到internet上的主机。考虑下面的代码示例: import socket, subprocess, re def get_ipv4_address(): ifc_resp = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE).communicate() patt = re.compile(r'inet\s*\
import socket, subprocess, re
def get_ipv4_address():
ifc_resp = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE).communicate()
patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
return patt.findall(ifc_resp[0])
def check_sock(addr):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((addr, 0))
s.connect(("www.google.com", 80))
s.close()
def main():
addrs = sorted(a for a in get_ipv4_address() if not a.startswith("127.0."))
print "Checking addresses " + ", ".join(addrs)
for addr in addrs:
print "Connecting via " + addr
check_sock(addr)
main()
当我运行此程序时,可以通过VPN IP地址毫无问题地建立连接。尽管程序挂起连接到本地网络的连接:
>>> python binddemo.py
Checking addresses 10.200.195.233, 192.168.2.33
Connecting via 10.200.195.233
Connecting via 192.168.2.33
^CTraceback (most recent call last):
File "binddemo.py", line 22, in <module>
main()
File "binddemo.py", line 20, in main
check_sock(addr)
File "binddemo.py", line 12, in check_sock
s.connect(("www.google.com", 80))
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
KeyboardInterrupt
指定给普通IP地址(而不是google主机)的连接同样会失败,所以我想这不是DNS查找造成的问题。有什么办法可以解决这个问题或者至少可以进一步研究吗?在客户端套接字上使用bind()
,而该客户端套接字不打算listen()
也不起任何作用。用于传出连接的接口完全取决于路由配置
您已设置了两个默认网关,但连接到wlan接口的网关具有比隧道设备更高的指标。因此linux总是将tuneling接口用作默认网关
下面是一个更深入的解释:
[编辑1]
仔细查看路由表后,删除隧道设备的默认网关应该可以解决问题,因为您还有一个网络路由设置,可以正确地将所有流量路由到vpn。因此,请尝试删除此项:
default via 10.200.195.1 dev tun0 proto static metric 50
因为这个将通过tun0
路由您的vpn流量:
10.200.195.0/24 dev tun0 proto kernel scope link src 10.200.195.233 metric 50
[编辑2]
如果希望通过隧道设备保留默认路由,可以使用网络名称空间
:
但是,您仍然无法从一个程序访问两个网络。最终的解决方案是:
echo "1 localwlan" >> /etc/iproute2/rt_tables
ip route add default table localwlan via 192.168.2.33 dev wlan0
ip rule add from 192.168.2.33 lookup localwlan
感谢@Christian Eichelman为我指明了正确的方向是否无法保留默认路线,并根据需要指定其他路线?我希望通过VPN保留默认设置。问题是:您的VPN的地址范围有限(10.200.195.0/24),因此您可以设置网络路由。internet没有:)因此您通常将默认gw指向面向internet的路由器。我的意思是,最终我希望绕过计算机的路由配置,在不同的VPN及其网关之间选择如何以编程方式路由流量。依赖路由对我没有任何帮助。我曾希望可以通过为套接字指定不同的传出IP地址来实现这一点。我也可以指定虚拟设备,比如ping-I dev
。如果您希望每个进程都这样做,现代内核支持网络名称空间
。这与python无关,您可以将不同的进程绑定到不同的接口。请查看以下答案:。请注意,您不能从同一进程访问两个网络。请为具有任何网络/子网范围的专用网络划分一个接口。
echo "1 localwlan" >> /etc/iproute2/rt_tables
ip route add default table localwlan via 192.168.2.33 dev wlan0
ip rule add from 192.168.2.33 lookup localwlan