使用树莓派搭建 PPTP VPN 的 WiFi 热点

1 背景

为了响应国家的号召,媳妇的公司也让在家办公了,她们公司也提供了 VPN 方便访问公司内网。但是 VPN 用的是 PPTP 协议,由于安全原因,macOS 已不再支持此协议,甚至从 Catalina 开始,从内核移除了相关代码。

因为 VPN 是公司提供的,因此不考虑更换协议的可能性,摆在面前的选项就只有:

  • 使用 Windows 办公。
  • 使用第三方 macOS VPN 客户端(但都是收费的)。
  • 自己折腾。

想到家里还有个正在吃灰的树莓派,正好可以练练手,因此选择了自己折腾。

2 方案

手头可用的材料有:

  • 树莓派 3B + 一只,这个型号预置了 WiFi 模块,无需另接无线网卡。
  • 支持树莓派的 Linux 系统:ArchLinux ARM

目标方案为:树莓派通过有线网连接 VPN,用 WiFi 做热点,将从热点进来的流量全部导向 VPN。macOS 只需要连接树莓派的热点,即可通过 VPN 访问公司内网。

3 操作步骤

首先分解一下需要进行的操作:

  • 连接 PPTP VPN。
  • 配置 WiFi 热点。
  • 将来自 WiFi 热点的流量导向 VPN。

下面就基于 ArchLinux ARM,介绍每一步的操作。

操作过程中的大部分指令,都需要以 root 权限执行,因此请先切换到 root 用户。如果不想切换到 root 用户,请在每个指令前加上 sudo

3.1 连接 PPTP VPN

在连接 VPN 之前,首先需要确保树莓派连接的有线网络的 IP 段,不与 VPN 的内网 IP 段相冲突。

假设 VPN 的内网 IP 段是 192.168.1.0/24,那么树莓派的有线网络 IP 段不能与这个 IP 段有任何交集,比如使用 172.16.1.0/24

3.1.1 安装软件包

1
pacman -Sy pptpclient

有些 Linux 发行版已经预置了这个软件包,安装前可以先执行 pptpsetup --help,检查一下软件包是否已经存在。

3.1.2 配置 VPN

1
2
3
4
5
# 这里我们创建了一个VPN配置,将其命名为:officevpn
pptpsetup --create officevpn \
--server <VPN服务器IP或域名> \
--username <VPN用户名> \
--password <VPN密码> --encrypt

3.1.3 连接 / 断开 VPN

1
2
3
4
5
# 连接VPN
pon officevpn

# 断开VPN
poff officevpn

3.1.4 查看 VPN 状态

执行命令 ip addr show,查看所有的网络连接。

如果列表中有一个名字以”ppp” 开头的网络连接,且成功分配了 IP,即表示 VPN 连接成功。

3.2 配置 WiFi 热点

配置 WiFi 热点时,同样也需要为热点网络选择一个子网 IP 段,这个 IP 段也是不能与 VPN 内网的 IP 段冲突,另外最好也不要与有线网络的 IP 段冲突,例如使用 10.1.1.0/24

3.2.1 安装软件包

1
pacman -Sy dnsmasq hostapd

如果你比较习惯使用 NetworkManager,也可以用它来配置热点,这里只是以 dnsmasq + hostapd 来举例。

3.2.2 配置 DHCP 客户端

首先我们需要为 WiFi 网卡配置一个静态 IP:10.1.1.1

备份并编辑文件”/etc/dhcpcd.conf”,在文件最后追加如下内容:

1
2
3
interface wlan0
static ip_address=10.1.1.1/24
nohook wpa_supplicant

重启服务:

1
systemctl restart dhcpcd

3.2.3 配置 dnsmasq

在这里,仅将 dnsmasq 作为 DHCP 服务器来使用。

备份并编辑文件”/etc/dnsmasq.conf”,在里面添加如下内容:

1
2
interface=wlan0
dhcp-range=10.1.1.2,10.1.1.255,255.255.255.0,24h

安装并启动 dnsmasq 服务:

1
2
3
4
5
6
7
8
# 安装服务
systemctl enable dnsmasq

# 启动服务
systemctl start dnsmasq

# 查看服务状态
systemctl status dnsmasq

3.2.4 配置 hostapd

hostapd 的配置文件为”/etc/hostapd/hostapd.conf”,如果文件已存在,建议将其改名备份,之后新建一份空白的同名文件,输入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface=wlan0

driver=nl80211
hw_mode=g
channel=11
ignore_broadcast_ssid=0

auth_algs=1
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
macaddr_acl=0

# 设置WiFi名称,这里为"RaspberryPi"
ssid=RaspberryPi
# 设置WiFi密码,这里为"12345678"
wpa_passphrase=12345678

配置中的”WiFi 名称” 和”WiFi 密码” 两项,可根据实际情况修改。其他参数,如果你不了解其意义,建议不要修改。

安装并启动 hostapd 服务:

1
2
3
4
5
6
7
8
# 安装服务
systemctl enable hostapd

# 启动服务
systemctl start hostapd

# 查看服务状态
systemctl status hostapd

3.2.5 测试热点

使用手机或者一台电脑,尝试搜索并连接前面配置的 WiFi。

如果能够成功连接到 WiFi,并分配到了一个在”10.1.1.2”~”10.1.1.255” 之间的 IP,即表示一切正常。

当然,这个阶段你还无法通过这个热点上网,这是接下来要做的事情。

3.3 流量转发

这里我们不需要任何第三方软件包,直接使用系统自带的 iproute2iptables 工具包来搞定。

请先通过如下命令,判断一下你的系统是否有对应的工具包:

1
2
3
4
5
# 测试iproute2
ip addr

# 测试iptables
iptables --version

回顾一下方案,我们的需求是将所有来自 WiFI 热点的流量,导向 VPN 连接。因此,首先需要为所有来自 WiFi 热点的数据包做一个标记,然后将这些数据包全部转发到 VPN 连接。

3.3.1 启用数据包转发

1
2
# 开启数据包转发
sysctl -w net.ipv4.ip_forward=1

为了让该配置在重启后仍然生效,创建文件”/etc/sysctl.d/ip-forward.conf”,并在其中添加如下内容:

1
net.ipv4.ip_forward=1

3.3.2 配置转发规则

在配置规则前,首先需要获取 VPN 连接的一些信息。

执行命令 ip addr show,找到 ppp 开头的 VPN 连接信息,例如:

1
2
3
4
4: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1496 qdisc fq_codel state UNKNOWN group default qlen 3
link/ppp
inet 192.168.1.222 peer 192.168.1.33/32 scope global ppp0
valid_lft forever preferred_lft forever

记下其中的连接名称(例子中为 ppp0)和 peer IP(例子中为 192.168.1.33)。

现在开始配置转发规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 这里我们自定义了一个路由表,将其编号定义为201

# 清空路由表201
ip route flush table 201

# 在路由表201中添加默认规则,将数据包路由到VPN服务器
ip route add default via 192.168.1.33 dev ppp0 table 201

# 为所有来自WiFi热点的数据包添加标记
iptables -t mangle -A PREROUTING -i wlan0 -j MARK --set-mark 0x1

# 将所有被标记的数据包发往路由表201
ip rule add fwmark 0x1 pri 100 lookup 201

# 将所有发往VPN连接的数据包,伪装成来自本机
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

配置完上述规则后,连接 WiFI 热点的设备,即可直接访问公司内网的资源。

3.3.3 自动配置

上一步配置的所有规则,都是不存盘的,因此每次连接 VPN 之后,都要重新配置。

所幸 pptpclient 提供了 hook 机制,当 pptp 连接建立成功时,它自动会执行”/etc/ppp/ip-up.d/“下面的所有”.sh” 脚本。因此我们可以创建一个 hook 脚本,实现自动配置规则。

在”/etc/ppp/ip-up.d/“下面创建文件” auto-hotspot.sh”,写入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh

# pptpclient调用此脚本时,会传入6个参数:
# 其中$1为VPN的连接名称,$5为VPN服务器IP。

TABLE_VPN=201

ip route flush table $TABLE_VPN
ip route add default via $5 dev $1 table 201

iptables -t mangle -A PREROUTING -i wlan0 -j MARK --set-mark 0x1
ip rule add fwmark 0x1 pri 100 lookup $TABLE_VPN
iptables -t nat -A POSTROUTING -o $1 -j MASQUERADE

最后,不要忘记为 hook 脚本添加执行权限:

1
chmod a+x /etc/ppp/ip-up.d/auto-hotspot.sh

4 参考资料