通过Wireguard将远程服务器的ip分配给本地使用

Wireguard+iptables实现网络层的转发

这几天一个朋友说她要在学校放一台服务器,但是拿不到独立的公网ip,于是我突然有了这么一个想法——能不能将远程服务器的ip分配给本地使用呢?这样就可以让本地用上独立的固定公网ip了,我的想法大概如下(如果远程服务器有两个公网ip):

  • 本地通过wireguard主动连接到远程的服务器
  • 远程服务器将发送到其中一个公网ip的请求全部转发给虚拟局域网中本地服务器对应的ip
  • 本地进行的响应也走wireguard

当然,现在已经有诸如frp等很成熟的端口转发工具了,如果只是单纯的转发一个端口、暴露一个服务之类的需求直接使用frp就好了。但是如果想实现低至网络层、全端口的数据包转发则可以使用这种方法,标题中所说的"分配",指的是实现网络层的转发,而不是真的给本地网卡分配一个公网ip,当然,在表现上来说,和本地分配了一个公网ip没什么区别。

想明白流程之后的实际操作不难,折腾了一会便实现了这个想法,一开始实验的时候用的是双ip的服务器,但是实际上单ip服务器也是可以的,操作见下文即可。

使用的机器:

  1. 双ip的justhost
  2. 单ip的腾讯云

使用wireguard组网

首先我们要在两台机器间建立一个虚拟局域网(除了wireguard,zerotier之类的软件也是可以的),先在本地与远程两台机器上安装wireguard,并生成密钥。

apt install wireguard
wg genkey  | tee privatekey | wg pubkey > publickey

/etc/wireguard/ 下创建配置文件 wg.conf:

在具有公网ip的服务器上配置如下:

[Interface]
# 客户端连接的端口
ListenPort = 16000
# 虚拟局域网中的ip
Address = 10.0.0.1/24
# 填上之前生成的私钥
PrivateKey = $PRIVATEKEY
# 下面两条是放行的iptables和MASQUERADE
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# 无公网ip的服务器设置
[Peer]
# 无公网ip的服务器公钥
PublicKey = $PUBLICKEY
AllowedIPs = 10.0.0.2/32

另外修改 /etc/sysctl.conf 添加 net.ipv4.ip_forward = 1 执行 sysctl -p 开启转发。

在没有公网ip的服务器上配置如下

[Interface]
# 虚拟局域网中的ip
Address = 10.0.0.2/24
# 客户端私钥
PrivateKey = CLIENTA_PRIVATE_KEY
# MTU(可选)
# MTU = 1420
# 监听端口(可选)
# ListenPort =

[Peer]
# Server
# Server 公钥
PublicKey = SERVER_PUBLICKEY
# Server IP:Port
Endpoint = 1.2.3.4:16000
# 通过 wireguard传输的 IP 列表
AllowedIPs = 10.0.0.0/24
# 强烈建议开启定期握手,不然远程服务器可能没办法主动连接上本地机器
PersistentKeepalive = 20

之后启动wireguard

wg-quick up wg
# 或者
systemctl start wg-quick@wg

另外,如果使用的是境外的机器用于转发,普通的udp跨境速度感人,Hysteria可以加速连接,并且隐藏wireguard的特征,但是relay_udp模式貌似存在一些问题,在我的测试中都没有速度,感兴趣的可以查看一下这篇文章使用Hysteria进行双边加速…国内的机器则不用太担心这点(除非机房限制了udp)。

实现流量转发

在组建了虚拟局域网之后我们就可以对流量进行转发了。下面两种情况要分开考虑:

  1. 远程服务器有多个公网ip(双栈也可以)
  2. 远程服务器只有一个公网ip

多ip服务器的转发

假设网络环境如下

远程服务器有双ip(双栈也可以) 1.1.1.1和2.2.2.2,虚拟局域网中的ip为10.0.0.1,本地机器只有局域网ip,虚拟局域网中的ip为10.0.0.2。我们需要将2.2.2.2给本地的机器使用,

本地的服务器使用1.1.1.1和远程服务器建立wg连接,之后的流程如下:

  1. 外部流量到 2.2.2.2
  2. iptables修改目的ip为 10.0.0.2
  3. 路由到wg虚拟网卡进行处理
  4. 经过wireguard到达本地
  5. 响应请求
  6. 经过wg虚拟网卡到达远程服务器
  7. iptables 修改源ip为2.2.2.2

我使用justhost来测试,他家创建服务器的时候就算选择了多个ip,但是创建出来只绑定了一个ip,所以我们还需要进行配置。

两个公网ip为:

  • 45.89.228.209 用于建立wireguard连接 (双栈服务器可以使用ipv6来建立连接)
  • 45.130.146.230 分配给本地使用

修改 /etc/netplan/50-cloud-init.yaml (Ubuntu18之后的配置文件,之前的版本为network/interfaces)

# network: {config: disabled}
network:
    version: 2
    ethernets:
        eth0:
            addresses:
            - 45.89.228.209/23
            - 45.130.146.230/23
            - 2a00:b700:2::7:156/64
            gateway4: 45.89.228.1
            gateway6: 2a00:b700:2::1
            match:
                macaddress: 5e:e7:6c:db:9f:83
            nameservers:
                addresses:
                - 77.88.8.8
                - 77.88.8.1
                - 2a00:b700::220
                - 2a00:b700:1::220
                search:
                - justhost.ru
            set-name: eth0

之后使用 netplan apply 应用配置,应用之后尝试 ping 45.130.146.230 已经可以获得回应了,但是有一个很奇怪的问题,我用 ifconfig 还是无法看见新分配的ip,但是使用 ip addr 是可以看见的。

通过Wireguard将远程服务器的ip分配给本地使用

分配好ip后,我们尝试将新分配到的45.130.146.230分配给本地的服务器使用。为了使连接不受影响,我们需要修改本地wireguard配置文件中对应peer的endpoint,使用45.89.228.209:16000来建立连接。

通过Wireguard将远程服务器的ip分配给本地使用

连接已建立

在虚拟局域网中ip如下:

10.0.0.2: 本地的服务器ip

10.0.0.10: 远程的服务器ip

之后我们需要在远程服务器上使用iptables进行一些修改 这两条命令也可以写到wireguard的postup和postdown参数中

# 首先需要实现将目的ip为45.130.146.230的数据包修改目的地址为10.0.0.2
iptables -t nat -I PREROUTING -d 45.130.146.230 -j DNAT --to-destination 10.0.0.2
# 因为wireguard修改了路由表,所以之后目的地址为10.0.0.2的数据包就会转发至10.0.0.2
# 另外需要将10.0.0.2的响应请求,源ip修改为 45.130.146.230
iptables -t nat -I POSTROUTING -s 10.0.0.2 -j SNAT --to-source 45.130.146.230
# 另外,数据包经过wg的时候被改写了源ip(变成10.0.010),这样会导致无法正常响应

Copy

服务端修改成这样后,就可以了,但是还有一个问题需要处理,此时在远程服务器上对wg接口抓包,这时是可以看见 xxx.xxx.xxx.xxx(来自公网的ip) -> 10.0.0.2 的icmp数据包的,但是在本地的服务器上对wg接口抓包,什么都看不见。

原因是本地的wg配置文件中只设置了 AllowedIPs = 10.0.0.0/24,也就是说只允许源ip和目的ip为10.0.0.0/24在wg上进行传输。

虽然设置成0.0.0.0/0,可以允许所有的包经过wg进行传输,但是本地的所有请求也会经过wireguard进行传输,但如果我们只希望本地服务器的被动响应走wg,而主动连接不经过wg,那么还需要再客户端上进行一些设置。

修改本地机器的 wg.conf,在[Interface]中添加如下字段

Table = 1
PostUp = ip rule add from 10.0.0.2 table 1; ip rule add to 10.0.0.0/24 table 1
PostDown = ip rule del from 10.0.0.2 table 1; ip rule add to 10.0.0.0/24 table 1

加上上面的字段后,wireguard会新建一个路由表,而不是直接在主路由表上进行修改,然后我们只需要让来自于wg的请求以及目的ip是虚拟局域网中的地址的请求根据这个表进行路由,而本地主动发出的请求根据主路由表路由,即可实现上面需要的功能。

然后执行 systemctl restart wg-quick@wg 重启wireguard即可。 可以看见延迟发生了变化

通过Wireguard将远程服务器的ip分配给本地使用

启动前

通过Wireguard将远程服务器的ip分配给本地使用

启动后

单ip服务器的转发

其实单ip服务器的转发也很简单,唯一的一点不同就是SNAT和DNAT的时候,需要忽略几个端口,比如需要忽略目的端口是wireguard监听端口(16000)的请求,如果我们还想要连接到用于中转的服务器,那么还需要忽略22端口。

单ip服务器转发使用腾讯云的机器进行,几家大厂的服务器都有个特点——网卡没有直接绑定公网ip。在建立好了虚拟局域网之后,我们要设置下面的转发规则: (multiport模块不支持 -p all参数)

iptables -t nat -I PREROUTING -d 127.0.0.1 -p tcp -m multiport ! --dports 22,16000 -j DNAT --to-destination 10.0.0.2
iptables -t nat -I PREROUTING -d 127.0.0.1 -p udp -m multiport ! --dports 22,16000 -j DNAT --to-destination 10.0.0.2

iptables -t nat -I POSTROUTING -s 10.0.0.2 -j SNAT --to-source 127.0.0.1

之后的在本地服务器上进行的设置和多ip服务器的设置一样,就不赘述了。

我使用的配置文件

  1. 本地服务器

    [Interface]
    # 虚拟局域网内的
    Address = 10.0.0.2/24
    # 客户端私钥
    PrivateKey = privatekey
    Table = 1
    PostUp = ip rule add from 10.0.0.2 table 1; ip rule add to 10.0.0.0/24 table 1
    PostDown = ip rule del from 10.0.0.2 table 1; ip rule del to 10.0.0.0/24 table 1
    [Peer]
    PublicKey = publickey1
    Endpoint = x.x.x.x:16000
    AllowedIPs = 10.0.0.1/32, 0.0.0.0/0
    PersistentKeepalive = 20
    [Peer]
    PublicKey = publickey2
    Endpoint = x.x.x.x:16000
    AllowedIPs = 10.0.0.10/32
    PersistentKeepalive = 20
    
  2. 多ip服务器

    [Interface]
    # 客户端连接的端口
    ListenPort = 16000
    Address = 10.0.0.10/24
    # 填上之前生成的私钥
    PrivateKey = privatekey
    # 下面两条是放行的iptables和MASQUERADE
    PostUp = iptables -t nat -I PREROUTING -d 45.130.146.230 -j DNAT --to-destination 10.0.0.2; iptables -t nat -I POSTROUTING -s 10.0.0.2 -j SNAT --to-source 45.130.146.230;
    PostDown = iptables -t nat -D PREROUTING -d 45.130.146.230 -j DNAT --to-destination 10.0.0.2; iptables -t nat -D POSTROUTING -s 10.0.0.2 -j SNAT --to-source 45.130.146.230
    [Peer]
    PublicKey = publickey
    AllowedIPs = 10.0.0.2/32
    
  3. 单ip服务器

    腾讯云等大厂的服务器绑定的一般都是内网ip,而非公网ip,这里是10.0.4.5

    [Interface]
    # 客户端连接的端口
    ListenPort = 16000
    Address = 10.0.0.1/24
    # 填上之前生成的私钥
    PrivateKey = privatekey
    
    PostUp = iptables -t nat -A PREROUTING -d 10.0.4.5 -p tcp -m multiport --dports 22,16000 -j ACCEPT; iptables -t nat -A PREROUTING -d 10.0.4.5 -p udp -m multiport --dports 22,16000 -j ACCEPT; iptables -t nat -A PREROUTING -d 10.0.4.5 -j DNAT --to-destination 10.0.0.2; iptables -t nat -A POSTROUTING -s 10.0.0.2 -j SNAT --to-source 10.0.4.5;
    
    PostDown = iptables -t nat -D PREROUTING -d 10.0.4.5 -p tcp -m multiport --dports 22,16000 -j ACCEPT; iptables -t nat -D PREROUTING -d 10.0.4.5 -p udp -m multiport --dports 22,16000 -j ACCEPT; iptables -t nat -D PREROUTING -d 10.0.4.5 -j DNAT --to-destination 10.0.0.2; iptables -t nat -D POSTROUTING -s 10.0.0.2 -j SNAT --to-source 10.0.4.5;
    # 无公网ip的服务器设置
    [Peer]
    # 无公网ip的服务器公钥
    PublicKey = publickey
    AllowedIPs = 10.0.0.2/32
    

参考

https://fuckcloudnative.io/posts/wireguard-docs-practice/#-dns

https://www.cnblogs.com/wanstack/p/7728785.html

https://www.liuvv.com/p/a8480986.html

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
VPS网络

iperf3 测试 VPS 本地连接最大速度

2021-5-7 15:33:12

Linux网络

CentOS7 下安装 SOCKS5 代理并使用 GOST 搭建加密中转隧道

2022-2-18 17:37:36

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
搜索