在OpenVPN客户端运行时将套接字绑定到本地IP地址块

时间:2017-02-21 09:52:26

标签: 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*\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 route
default via 10.200.195.1 dev tun0  proto static  metric 50 
default via 192.168.2.1 dev wlan0  proto static  metric 600 
10.200.195.0/24 dev tun0  proto kernel  scope link  src 10.200.195.233  metric 50 
62.113.253.4 via 192.168.2.1 dev wlan0  proto static  metric 600 
169.254.0.0/16 dev wlan0  scope link  metric 1000 
192.168.2.0/24 dev wlan0  proto kernel  scope link  src 192.168.2.33  metric 600 

指定到普通IP地址(而不是谷歌主机)的连接同样失败,所以我认为这不是DNS查找造成麻烦。任何想法如何解决或至少进一步调查?

2 个答案:

答案 0 :(得分:1)

在不会bind()的客户端套接字上使用listen()没有做任何事情。用于传出连接的接口完全取决于您的路由配置。

您已设置两个默认网关,但进入您的wlan界面的网关比您的隧道设备具有更高的metric。所以linux总是将tuneling接口用作默认网关。

以下是一个更好,更深入的解释:https://serverfault.com/questions/648276/routing-selection-specificity-vs-metric

[编辑1]

在更仔细地查看路由表之后,删除隧道设备的默认网关应该可以解决您的问题,因为您还有一个网络路由设置,可以正确地将所有流量路由到您的VPN。所以尝试删除这个:

default via 10.200.195.1 dev tun0  proto static  metric 50 

因为这个会将您的vpn流量路由到tun0

10.200.195.0/24 dev tun0  proto kernel  scope link  src 10.200.195.233  metric 50 

[编辑2]

如果您想通过隧道设备保留默认路由,可以使用network namespaceshttps://superuser.com/questions/241178/how-to-use-different-network-interfaces-for-different-processes/750412#750412

但您仍然无法从单个程序访问这两个网络。

答案 1 :(得分:0)

最终解决了什么:

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指出我正确的方向