shynome / shynome.github.io

8 stars 0 forks source link

使用tinc vpn让没有公网ip的节点也能联网 #36

Open shynome opened 3 years ago

shynome commented 3 years ago

title: 使用tinc vpn让没有公网ip的节点也能联网

简介

使用 tinc redict gateway 让不能访问网络的内网机器通过可访问的机器访问网络

并无太大的实际用途, 因为 tinc 是单核的, 转发能力有限是 300M 左右

tinc 介绍

tinc 目录结构

/etc/tinc/myvpn/
├── hosts
│   ├── server
│   ├── server-down
│   ├── server-up
│   └── client
├── rsa_key.priv
├── tinc.conf
├── tinc-down
└── tinc-up

myvpn 目录名是 tinc 网络名称, 可随意更换
hosts/ 目录下面是节点信息文件
server-upserver-downserver 连接成功和断开连接后执行的脚本, 一般情况下不会添加, 但这次要通过其他 tinc 节点上网, 所以会用到
tinc-uptinc-down脚本设置路由, 蛮重要的, 没设置的话就和没组网一样
tinc.conf tinc 配置文件, 设置连接哪些节点, 网卡叫什么名字, 自己叫啥

这里假定内网里有两台机器 192.168.0.10(可联网) 和 192.168.0.11(不联网)
我们设定 myvpn 网段为 10.10.10.0/24, 网关服务器的 myvpn 地址选为 10.10.10.1/32 称为server, 待联网机器地址选为10.10.10.2/32 称为client, 便有了如下节点信息:

# /etc/tinc/myvpn/hosts/server
Subnet = 10.10.10.1/32
Address = 192.168.0.10
# 下面这个配置是作为网关转发所必需的
Subnet = 0.0.0.0/0
# /etc/tinc/myvpn/hosts/client
Subnet = 10.10.10.2/32
Address = 192.168.0.11

tinc 组网

  1. mkdir -p /etc/tinc/myvpn/hosts && cd /etc/tinc/myvpn/

  2. nano tinc.conf 记得把server换成当前节点的名称

    Name = server
    Interface = myvpn
    # client节点需要设置主动连接的节点, server节点不用
    # ConnectTo = server
  3. nano hosts/server 记得把10.10.10.1/32换成当前节点的 ip

    Subnet = 10.10.10.1/32
    Address = 192.168.0.10
    # 下面这个配置是作为网关转发所必需的
    Subnet = 0.0.0.0/0
  4. tincd -n myvpn -K 4096 生成节点密钥 rsa_key.priv 和追加公钥到 hosts/server

  5. nano tinc-up 记得把10.10.10.1/32换成当前节点的 ip

    #!/bin/sh
    ip link set $INTERFACE up
    ip addr add 10.10.10.1/32 dev $INTERFACE
    ip route add 10.10.10.0/24 dev $INTERFACE
    # 下面两条是作为网关转发所需的, 不做网关转发的话去掉
    echo 1 >/proc/sys/net/ipv4/ip_forward
    iptables -t nat -A POSTROUTING -j MASQUERADE
  6. nano tinc-down

    #!/bin/sh
    ip link set $INTERFACE down
  7. chmod +x tinc-* 赋予脚本可执行权限

  8. client 也按上面步骤设置好了后, 和 server 交换 hosts/ 目录下的节点信息, 交换好之后的目录 两台服务器的目录都应该像这样:

    /etc/tinc/myvpn/
    ├── hosts
    │   ├── server
    │   └── client
    ├── rsa_key.priv
    ├── tinc.conf
    ├── tinc-down
    └── tinc-up

测试 tinc 连通性

  1. server节点执行 tincd -n myvpn -D -d 2
    -D 是保持前台运行
    -d 2 是日志等级
  2. client节点执行 tincd -n myvpn
  3. 查看server节点是否有client connectted之类的连接信息出现
    没有的话, 检查client节点的tinc.conf文件的ConnectTo = server是否被注释掉了
  4. client节点执行ping 10.10.10.1看组网是否成功, 不通的话
    检查tinc-up脚本是否有可执行权限, 路由配置内容是否正确, 不正确的话修改正确后重启tinc
    重启命令: 杀死当前运行的进程:tincd -n myvpn -k, 再启动:tincd -n myvpn

ping 通之后, 退出当前运行的tinc进程, 让systemd来管理tinc服务
退出方式: server节点ctrl+c, client节点tincd -n myvpn -k

通过 server 网关上网

终于讲到这篇文章的核心了, 在tinc组网成功的基础上添加server-upserver-down脚本实现上网
下面操作都是在client节点上操作

  1. nano hosts/server-up 注意: VPN_GATEWAYserver的节点地址, 不同的话自行更换

    #!/bin/sh
    VPN_GATEWAY=10.10.10.1
    ORIGINAL_GATEWAY=`ip route show | grep ^default | cut -d ' ' -f 2-5`
    
    ip route add $REMOTEADDRESS $ORIGINAL_GATEWAY
    ip route add $VPN_GATEWAY dev $INTERFACE
    ip route add 0.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
    ip route add 128.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
  2. nano hosts/server-down

    #!/bin/sh
    VPN_GATEWAY=10.10.10.1
    ORIGINAL_GATEWAY=`ip route show | grep ^default | cut -d ' ' -f 2-5`
    
    ip route del $REMOTEADDRESS $ORIGINAL_GATEWAY
    ip route del $VPN_GATEWAY dev $INTERFACE
    ip route del 0.0.0.0/1 dev $INTERFACE
    ip route del 128.0.0.0/1 dev $INTERFACE
  3. chmod +x hosts/server-* 赋予可执行权限

  4. systemctl restart tinc@myvpn 重启tinc@myvpn服务

  5. curl ip.sb 测试client节点是否能上网了
    不能的话先停掉systemctl stop tinc@myvpn, 再用tincd -n myvpn -D -d 2看是哪里出问题了

反思

我为什么要写这篇文章呢? 明明如此简单, 只要在client节点添加server-upserver-down脚本就可以了的
这是因为官方教程里少了这句 iptables -t nat -A POSTROUTING -j MASQUERADE 导致我一直在琢磨哪里出错了, 明明 Subnet = 0.0.0.0/0echo 1 >/proc/sys/net/ipv4/ip_forward 我都添加了, 为什么还是不能联网, 最后是因缘巧合之下我发现我用 docker 搭建的 tinc 服务节点可以用来当作网关, 于是在它的配置里找到了不同之处, 这缺失的一句脚本 https://github.com/vimagick/dockerfiles/blob/master/tinc/docker-entrypoint.sh#L13

一些小技巧

  1. 如何 ssh 到没有公网 ip 的内网主机呢?
  2. ssh -J root@1.1.1.1 root@172.10.10.1 通过-J选项使用有公网 ip 的内网主机作为跳板机连接
shynome commented 3 years ago

更多小技巧

使用 webdav 挂载 hosts 目录以便中心化管理证书

这里示例用的 webdav 服务是 nextcloud, 它可以把文件编辑权限共享给成员而且是老牌文件管理服务了

在 nextcloud 里新建一个文件夹 tinc-hosts 将其以只读共享给特定组的成员, 之后再将其中的公钥文件编辑权限开放给 公钥拥有者, 这样他们要更新公钥的话可以自己更新

之后新建一个账号加入该组, 再使用该只读账号权限 webdav 挂载共享文件夹 tinc-host 到对应网络的 hosts 文件夹

端口转发

#!/bin/sh
# node-up
iptables -t nat -A PREROUTING -p tcp -d 10.13.0.4 --dport 3005 -j DNAT --to 10.13.0.1:3005
#!/bin/sh
# node-down
iptables -t nat -D PREROUTING -p tcp -d 10.13.0.4 --dport 3005 -j DNAT --to 10.13.0.1:3005

在小水管带宽下加快速度

# 使用压缩减小数据量大小
Compression = 10
# 使用TCP绕过UDP Qos限制
TCPOnly = yes
# 1.1 版本才有, 不自动连接节点
AutoConnect = no
shynome commented 2 years ago

玩具应用场景

重申一次: tinc 单核处理的带宽有限只有300M

故障转移

两个节点设置成一样的内网 ip 地址时会优先选择名字排序更靠前存活的节点, 这样可保证有任意一台存活时能继续使用(当然这两台服务器要能提供一样的服务