我正在尝试配置自定义 VPN 的网络设置客户图书馆。
我无法理解的是
我需要能够在正常的 VPN 设置中转发流量,以便我的 C++ 脚本可以读取/写入隧道。如果我没记错的话,设置应该是这样的:
Normal Setup How I think my setup should be
------------------------------------------------------------
Start → Aplication → Finish Start → Aplication → Finish
↓ ↑ ↓ ↑
iface-enp0s3 iface-enp0s3
↓ ↑ ↓ ↑
interwebs iface-tun1
↓ ↑
c++ script
↓ ↑
vpn-server
↓ ↑
interwebs
我确实知道我的 C++ 脚本目前无法执行此操作,目前它只是从适配器读取数据tun1
。目前,这就是我试图实现的全部目标。但是,我似乎无法让路由正常工作。
当我访问http://google.com从我的客户端系统中,我希望看到这些数据包显示在 C++ 脚本中,并且流量不会流向其他地方。
一旦我能够正确地路由所有流量不包括港口使用隧道接口通过 C++ 脚本连接 VPN 后,我将开始通过 VPN 客户端库发送它。
据我所知,C++ 脚本目前可以正常工作。当我 ping 10.0.0.2(适配器tun1
)时,我可以看到数据包通过。
我尝试了一些不同的事情,即以下几点:
sudo iptables -t nat -A POSTROUTING --出接口 tun1 -j MASQUERADE
sudo iptables -A FORWARD --入接口 enp0s3 -j ACCEPT
这不起作用。
注意:我已经确保
net.ipv4.ip_forward
设置为1
并且我已经运行了sudo sysctl -p
。
有关当前设置的信息请参见下文。
注意:我正在运行 Ubuntu 16.04 桌面。
我当前的适配器
注意:enp0s3 是我的主适配器。它在虚拟机上运行。enp0s3 是我的互联网连接。
enp0s3 Link encap:Ethernet HWaddr 08:00:27:ea:97:d2 inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0 inet6 addr: fe80::8ec8:60b7:f404:77c5/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:58668 errors:0 dropped:0 overruns:0 frame:0 TX packets:39067 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:39002535 (39.0 MB) TX bytes:7442839 (7.4 MB) tun1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 inet addr:10.0.0.1 P-t-P:10.0.0.2 Mask:255.255.255.255 inet6 addr: fe80::fed9:4107:8688:8501/64 Scope:Link UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:16 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:500 RX bytes:0 (0.0 B) TX bytes:984 (984.0 B)
如何设置tun1
适配器
$ sudo ip tuntap add dev tun1 模式 tun
$ sudo ifconfig tun1 10.0.0.1 dstaddr 10.0.0.2 up
我正在听的 C++ 脚本tun1
// Includes ommited.
using namespace std;
typedef void data_receiver(char* data, int length);
struct receive_handle {
data_receiver* receiver;
} typedef receive_handle;
// Function used to retrieve the interface.
static int if_nametofd(char *name)
{
int interface = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(interface, TUNSETIFF, &ifr)) {
perror("Cannot get TUN interface");
exit(1);
}
return interface;
}
// Called when a packet is received from the tun0 interface.
void received_data(char* data, int length)
{
// Truncate the packet so that we only see the first 15 bytes.
// This way we don't spam the console.
for(int i=0; i<15; ++i)
std::cout << std::hex << (int)data[i];
std::cout << endl;
}
int main()
{
cout << "Getting interface..." << endl;
int iface = if_nametofd("tun1");
cout << "Using interface: " << iface << endl;
cout << "Creating handler..." << endl;
receive_handle* handle = (receive_handle*)malloc(sizeof(receive_handle));
handle->receiver = received_data;
char packet[1024];
cout << "Listening..." << endl;
while (true)
{
if (read(iface, packet, sizeof(packet)) > 0) {
handle->receiver(packet, sizeof(packet));
}
}
return 0;
}
该脚本的唯一目的是锁定tun1
适配器并不断从中读取数据。
答案1
您需要更改工作站的默认网关。如果您发出以下命令,您将看到系统默认网关。
ip route show table main
default via 1.2.3.4 dev wanif
您可以使用 ip route replace (man ip-route) 来更改它。
更好的是,您可以使用开放 vpn 技巧来覆盖默认路由,而不必删除它(--redirect-gateway def1)。
这项工作通过添加两条覆盖整个 IPv4 地址空间的路由来实现。由于这两条路由都比默认路由更具体,因此默认路由实际上被覆盖了。
这是这样做的:
ip route add 0.0.0.0/1 via 10.0.2.15 dev tun1
ip route add 128.0.0.0/1 via 10.0.2.15 dev tun1
其中 10.0.2.15 是您的隧道本地端点。
由于您的脚本需要“通过常规互联网”连接到某个地方以提供一些有意义的隧道服务,因此您需要像这样添加远程端点,以避免受到上述规则的覆盖:
ip route add 7.8.9.10/32 via 1.2.3.4 dev wanif
其中 7.8.9.10 是您的远程端点,1.2.3.4 是您的 ISP 默认网关。
记住路由规则的基本规则:最具体的规则优先于不太具体的规则