TOC

VPN 与 NAT

我公司办公环境需要用到 OpenVPN,之前允许一个账号在两处登录,现在处于安全考虑只允许一处登录了。
然后,我就不方便了,因为我办公环境有两台电脑(台式机 Windows,笔记本 Ubuntu)都需要接入 VPN。

现在采用的方案

  • 台式机(Windows)设置网关为笔记本的内网 IP
  • 笔记本(Ubuntu)连上 VPN
  • 笔记本上设置 SNAT:

    sudo iptables -t filter -A FORWARD -s <台式机IP> -d 10.0.0.0/8 -j ACCEPT
    sudo iptables -t filter -A FORWARD -s 10.0.0.0/8 -d <台式机IP> -j ACCEPT
    sudo iptables -t nat -A POSTROUTING -s <台式机IP> -d 10.0.0.0/8 -j SNAT --to <笔记本VPN分配IP>
    

在 Windows 上设置路由,只把 10 网段转发到笔记本这边:

route print
route add 10.0.0.0 mask 255.0.0.0 <笔记本IP> -p
# -p 表示永远有效

Update at 2021-05-28

在 SHELL 配置文件中注入以下函数,方便快捷:

function ipforward {
    TARGET_IP='台式机IP'
    TARGET_NET='内网网络, 比如:10.0.0.0/8'

    SNAT_Rules=`sudo iptables -t nat -nL --line-numbers | grep SNAT`
    if [ -n "$SNAT_Rules" ]
    then
        echo 'Found SNAT bellow:'
        echo $SNAT_Rules
        echo '--------------------------------------------------------------------------------'
        echo 'Delete all SNAT rules...'
        for Rule_Num in `printf $SNAT_Rules | awk '{print $1}'`;
        do
            echo "Delete SNAT Rule (num: $Rule_Num)"
            sudo iptables -t nat -D POSTROUTING $Rule_Num
        done;
    else
        echo 'No SNAT rules found!'
    fi
    echo '--------------------------------------------------------------------------------'
    VPN_IP=`ip addr show tun0 | grep -F "inet " | awk '{print $2}'`
    echo "IP forword: $VPN_IP"
    sudo iptables -t nat -A POSTROUTING -s $TARGET_IP -d $TARGET_NET -j SNAT --to $VPN_IP
    echo '--------------------------------------------------------------------------------'
    sudo iptables -t nat -nL --line-numbers | grep SNAT
    echo '--------------------------------------------------------------------------------'
    echo 'OK!'
}

可能需要的操作

允许转发

我确定和这个有没有关系,反正我的电脑上是 1

cat /proc/sys/net/ipv4/ip_forward
# 允许转发
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

关闭防火墙

sudo systemctl disable ufw firewalld
sudo systemctl stop ufw firewalld

取消 iptables 中其他规则

# 如果不知道什么意思就先不要执行
# 还需要加上 -t filter|nat|mangle|raw|security
sudo iptables -vnL # 先看看都是些啥
sudo iptables -F # 清空所有规则
sudo iptables -X # 删除用户自定义链

修复 Windows HOSTS 文件

参考:Windows 10 修改 Hosts 文件

需要访问的内网域名都需要 dig 一遍,加到 Windows 主机的 HOSTS 文件。

function hosts.config () {
    domains=(
        home.internel.net
        code.internel.net
        docs.internel.net
    )
    for i in $domains; do printf "%-12s\t%s\n" $(dig +short $i) $i; done;
}

# 执行:
hosts.config | sort -k2

常用操作

别名:

vpn='vpn.status; vpn.stop; vpn.start; sleep 1; vpn.status; vpn.check'
vpn.check='/bin/ping -w 10 home.internel.net'
vpn.start='sudo systemctl start openvpn@client && echo started'
vpn.status='systemctl status -l --no-pager openvpn@client'
vpn.stop='sudo systemctl stop openvpn@client && echo stoped'

笔记本上使用的是:

sudo apt install -y openvpn

配置好 VPN 之后,VPN 的 DNS 没有配到 systemd-resolved,我这么搞定的:

sudo apt install -y openvpn-systemd-resolved
sudo tee /etc/openvpn/client.conf <<EOF
script-security 2
setenv PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
up /etc/openvpn/update-systemd-resolved
up-restart
down /etc/openvpn/update-systemd-resolved
down-pre
dhcp-option DOMAIN-ROUTE .
EOF

Update @ 2022-06-29

由于一些特殊原因,需要将指定特定的 IP 走 VPN,操作如下:

Windows 上执行:

route add <特定IP> mask 255.255.255.255 <笔记本IP> -p

Ubuntu 上执行:

sudo iptables -t nat -A POSTROUTING -s <台式机IP> -d <特定IP> -j SNAT --to <笔记本IP>
sudo iptables -t filter -A FORWARD -s <台式机IP> -d <特定IP> -j ACCEPT
sudo iptables -t filter -A FORWARD -s <特定IP> -d <台式机IP> -j ACCEPT

然后就可以了。