Skip to main content

tinc

caution
  • tinc 1.1 还不足够稳定
  • 单线程 - 性能有限
tip
  • 联通性很好
  • Switch 模式支持 L2
  • macOS
    • 目前已经不支持 tuntap
      • 默认使用 utun=tun - 只能用 Router 模式
      • 不支持 tap - 不能使用 Switch 模式
    • brew 没有 tinc-pre,需要自己添加
# 推荐使用 tinc-pre 1.1 版本
# 配置更方便使用更简单
apk add tinc-pre

sudo modprobe tun
# echo tun >> /etc/modules
echo tun | sudo tee /etc/modules-load.d/tinc.conf

# 基础配置
# NETNAME 配置生成在 /etc/tinc/first/
NETNAME=first tinc init first
tinc set Interface tun0
tinc set AddressFamily ipv4
# 第一个节点可考虑不设置链接节点
tinc set ConnectTo other
# 变量设置可以指定 host
tinc set sec.Subnet=10.0.0.2/32

# 在配置单个网络时, 设置个别名会比较方便, 使用不同目录或 pid 也可以这样操作
alias tinc='tinc -n main'
# 操作指定网络名时, 可使用环境变量
export NETNAME=main
tinc dump nodes
# 如果执行的命令比较多, 也可以加入交互模式操作
tinc -c .

ADDRESS=10.0.0.1
NETMASK=255.255.255.0
cat > tinc-up << SH
#!/bin/sh
ifconfig \$INTERFACE $ADDRESS netmask $NETMASK
SH
cat > tinc-down << SH
#!/bin/sh
ifconfig \$INTERFACE down
SH
chmod +x tinc-*

tincd -Dd4

# 导入别处 export 的配置
tinc import

# 生成邀请码
# 最简便的配置方式
tinc invite 节点名
# 加入
# 会在远程添加主机信息
# 会使用相同的 netname
# tinc-up 和 tinc-down 需要自己配置
tinc join 邀请码

tinc -n main invite thd

# 配置要启动的网络
# NETWORK: main
# 会使用 /etc/tinc/main 配置
nano /etc/conf.d/tinc.networks
rc-service tincd start
# 自启动
rc-update add tincd
# 启动后可以查看日志, 1-5
tinc -n main log 5

# Docker
# ======
# 先在 docker 中进行配置和测试
NETNAME=name
docker run --rm -it -e NETNAME=$NETNAME --cap-add=NET_ADMIN --device=/dev/net/tun -v $PWD/tinc:/etc/tinc wener/tinc sh
# 导入配置
docker run --rm -it -e NETNAME=$NETNAME -v $PWD/tinc:/etc/tinc wener/tinc tinc import
# 启动
docker run -d --restart always \
--net host --cap-add=NET_ADMIN --device=/dev/net/tun \
-e NETNAME=$NETNAME -v $PWD/tinc:/etc/tinc \
--name tinc-$NETNAME wener/tinc
# macOS
# http://tuntaposx.sourceforge.net/
# 新版没有了 devel 参数
# https://github.com/Homebrew/homebrew-core/tree/master/Formula/tinc.rb
# curl https://raw.githubusercontent.com/wenerme/homebrew-core/tinc-pre/Formula/tinc-pre.rb > /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/tinc-pre.rb
cat << RB > /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/tinc-pre.rb
class TincPre < Formula
desc "Virtual Private Network (VPN) tool"
homepage "https://www.tinc-vpn.org/"
url "https://www.tinc-vpn.org/packages/tinc-1.1pre18.tar.gz"
sha256 "2757ddc62cf64b411f569db2fa85c25ec846c0db110023f6befb33691f078986"

depends_on "lzo"
depends_on "openssl"

def install
system "./configure", "--prefix=#{prefix}", "--sysconfdir=#{etc}",
"--with-openssl=#{Formula["openssl"].opt_prefix}"
system "make", "install"
end

test do
assert_match version.to_s, shell_output("#{sbin}/tincd --version")
end
end
RB
# fetch 会显示 sha256 - 可能需要代理
brew fetch --build-from-source tinc-pre
brew install --build-from-source tinc-pre

# utun
# ===============
# 在 mac 下, tinc 支持 utun, 可能需要 root 权限
tinc set DeviceType utun

# 确保路径存在, 否则 pid 会存在当前目录
mkdir -p /usr/local/Cellar/tinc/1.1pre17/var/run/

# tun/tap
# ===============
# tuntap 10.13 会安装失败
brew cask install tuntap
# /Library/Extensions/tap.kext
# /Library/Extensions/tun.kext
# /Library/StartupItems/tap
# /Library/StartupItems/tun

# 手动加载
sudo kextload /Library/Extensions/tun.kext
# 失败日志
sudo dmesg
# tun: could not register PF_INET protocol family: 17
# Kext net.sf.tuntaposx.tun start failed (result 0x5).
# Kext net.sf.tuntaposx.tun failed to load (0xdc008017).
# Failed to load kext net.sf.tuntaposx.tun (error 0xdc008017).

# 查看现有的
kextstat | grep tun
# 写在
sudo kextunload -b 名字

# https://tunnelblick.net
# 包含了新的 kext

# 查看具体出错信息
sudo kextutil /Volumes/Tunnelblick/Tunnelblick.app/Contents/Resources/tun-signed.kext

sudo kextutil /Library/Extensions/tun.kext
# Memory allocation failure.
# Untrusted kexts are not allowed

tinc-up

#!/bin/sh
brctl addif br0 $INTERFACE
ifconfig $INTERFACE 0.0.0.0 promisc up

# 该节点作为路由
# iptables -I FORWARD -i $INTERFACE -j ACCEPT
# iptables -t nat -A POSTROUTING -d 10.88.0.0/16 -o $INTERFACE -j MASQUERADE

tinc-fw

#!/bin/sh
iptables -I INPUT -p udp --dport 20656 -j ACCEPT
iptables -I INPUT -p tcp --dport 20656 -j ACCEPT
iptables -I INPUT -i tinc -j ACCEPT
iptables -I FORWARD -i tinc -j ACCEPT

完整的网络配置

# 主节点
export NETNAME=mynet
export NODE=mynet

tinc init $NETNAME
cd /etc/tinc/$NETNAME

# 配置启动脚本
ADDRESS=10.66.1.1
NETMASK=255.255.0.0
cat > tinc-up <<SH
#!/bin/sh
ifconfig \$INTERFACE $ADDRESS netmask $NETMASK
SH
cat > tinc-down <<SH
#!/bin/sh
ifconfig \$INTERFACE down
SH
chmod +x tinc-*

# 配置主节点地址
# 用于其它节点请求的地址, 如果有外网地址
tinc set $NODE.Address=$(curl ipv4.icanhazip.com)
# 如果不想使用默认端口
tinc set $NODE.Port=12345
# 私有子网
tinc set $NODE.Subnet=$ADDRESS/32
# 启动
tinc start

# 邀请其它节点
tinc invite home

# home 节点
# =============
export NETNAME=mynet
export NODE=home
tinc join <INVITE>

cd /etc/tinc/$NETNAME

# 配置启动脚本
ADDRESS=10.66.1.2
NETMASK=255.255.0.0
cat > tinc-up <<SH
#!/bin/sh
ifconfig \$INTERFACE $ADDRESS netmask $NETMASK
SH
cat > tinc-down <<SH
#!/bin/sh
ifconfig \$INTERFACE down
SH
chmod +x tinc-*

# 如果不想使用默认端口
tinc set $NODE.Port=45678
# 私有子网
tinc set $NODE.Subnet=$ADDRESS/32

# svr 节点
# =============
# 如果不能安装 tinc-1.1+ 则可以使用 docker
export NETNAME=mynet
export NODE=home
docker run --rm -it -e NODE=$NODE -e NETNAME=$NETNAME --cap-add=NET_ADMIN --device=/dev/net/tun -v /data/tinc/$NETNAME/$NODE:/etc/tinc wener/tinc sh

tinc join <INVITE>

cd /etc/tinc/$NETNAME
# 配置启动脚本
ADDRESS=10.66.1.3
NETMASK=255.255.0.0
cat > tinc-up <<SH
#!/bin/sh
ifconfig \$INTERFACE $ADDRESS netmask $NETMASK
SH
cat > tinc-down <<SH
#!/bin/sh
ifconfig \$INTERFACE down
SH
chmod +x tinc-*

# 如果不想使用默认端口
tinc set $NODE.Port=45678
# 私有子网
tinc set $NODE.Subnet=$ADDRESS/32
# 退出配置容器
exit
# 运行服务
docker run -d --restart always -v /etc/localtime:/etc/localtime:ro \
--cap-add=NET_ADMIN --device=/dev/net/tun \
-e NETNAME=$NETNAME \
-v /data/tinc/$NETNAME/$NODE:/etc/tinc \
--name tinc-$NETNAME-$NODE wener/tinc

FAQ

traps: tincd[3995] general protection fault ip:7f6ad09944eb sp:7ffda3da5ea8 error:0 in ld-musl-x86_64.so.1[7f6ad098b000+46000]

tinc pre 运行不稳定,务必配置 openrc 自动重启

Failed to verify SIG record from infra

签名验证失败,尝试重新 invite

Got REQ_KEY from node while we already started a SPTPS session!

相同 key 或相同 名字?

Peer tries to roll back protocol version to 17.0

使用 1.0 协议

ExperimentalProtocol = no

Could not open /dev/net/tun: No such file or directory

加载 tun 内核模块

modprobe tun
echo tun >> /etc/modules

route

sysctl net.ipv4.ip_forward
sysctl -w net.ipv4.ip_forward=1
# 1. 允许包转发, 会将 eth0 子网的转发到 mynet, 需要在网关节点添加 eth0 的子网才能做到互通
# iptables -L --line-number -nv
iptables -I FORWARD -i mynet -j ACCEPT
iptables -I FORWARD -i eth0 -j ACCEPT

# 2. NAT 使得 eth0 子网能访问私网
# 如果做了桥接, 这里需要换成桥接网卡
# iptables -t nat -L --line-number -nv
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# 如果有多个私网, 也可以考虑限制目标网段
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.10.0.0/16 -o mynet -j MASQUERADE

# 创建用于 docker 使用的网络
# 假设当前节点的子网是 10.10.1.0/24 当前节点的地址是 10.10.1.0
docker network create \
--driver=bridge \
--subnet=10.10.0.0/16 \
--ip-range=10.10.1.0/24 \
--gateway=10.10.1.0 \
--aux-address="my-host=10.10.1.1" \
-o com.docker.network.bridge.name=brmynet \
brmynet
# 允许桥接网卡转发
iptables -I FORWARD -i brmynet -j ACCEPT
# 将 tinc 作为该桥接的 slave
ip li set master brmynet dev mynet
# 或者在 tinc-up 中设置
cat > tinc-up << SH
#!/bin/sh
ip li set master br$INTERFACE dev $INTERFACE
ip li set dev $INTERFACE up
SH

# 调试
tcpdump -nni mynet icmp

How can I set my linux box as a router to forward ip packets? https://askubuntu.com/q/227369/267103

Linux IP Masquerade HOWTO http://tldp.org/HOWTO/IP-Masquerade-HOWTO/

iptables -I FORWARD -i brwenet -j ACCEPT

tinc 1.0 升级 1.1

tinc -n NETNAME generate-ed25519-keys

tinc.netname

sudo modprobe tun
echo tun | sudo tee /etc/modules-load.d/tinc.conf

sudo nano /etc/init.d/tinc.netname
sudo chmod +x /etc/init.d/tinc.netname

sudo ln -sf /etc/init.d/tinc.netname /etc/init.d/tinc.$NETNAME
sudo service tinc.$NETNAME start
sudo rc-update add tinc.$NETNAME
#!/sbin/openrc-run
supervisor=supervise-daemon

name="TincVPN Daemon"
description="tinc is a Virtual Private Network (VPN) daemon that uses tunnelling and encryption to create a secure private network between hosts on the Internet."
description_reload="Reload configuration without exiting"

# tinc.netname -> netname
NETNAME=${RC_SVCNAME##*.}
: ${TINC_DEBUG:=0}

command=/usr/sbin/tincd
command_args="-n $NETNAME -d $TINC_DEBUG $TINC_OPTS"
command_args_foreground="-D"

TINC_LOGFILE="${TINC_LOGFILE:-/var/log/${RC_SVCNAME}.log}"
TINC_ERRFILE="${TINC_ERRFILE:-${TINC_LOGFILE}}"
TINC_OUTFILE="${TINC_OUTFILE:-${TINC_LOGFILE}}"
supervise_daemon_args="--stderr \"${TINC_ERRFILE}\" --stdout \"${TINC_OUTFILE}\""

extra_started_commands="reload"
retry="${TINC_RETRY:-TERM/60/KILL/10}"

depend() {
use logger dns
need net
}

checkconfig() {
# warn this if not found
if [ ! -f "/etc/tinc/$NETNAME/tinc.conf" ]; then
eerror "No VPN network configured"
return 1
fi
return 0
}

reload() {
ebegin "Reloading configuration"
$supervisor $RC_SVCNAME --signal HUP
eend $?
}