Press "Enter" to skip to content

Ubuntu IPsec To MikroTik Tunnel

使用指南

  1. 修改脚本第 13 行的 MIKROTIK_LAN_SUBNETS,填入你的 MikroTik 需要通过 Ubuntu 代理上网的所有内网网段(例如你的 LAN 是 192.168.88.0/24 和 10.10.10.0/24),多个网段用空格隔开即可。
  2. 运行 ./脚本名称.sh restart (如果你之前装过,直接重启) 或 ./脚本名称.sh install(全新安装)。
  3. MikroTik 端的配置不需要使用 masquerade 伪装,你只需要通过 Mangle 标记特定的内网流量,然后添加一条路由 dst-address=0.0.0.0/0 gateway=10.100.40.2 (指向Ubuntu内网) 即可。
  4. 现在你可以通过 ./脚本名称.sh status 来观察 Ubuntu 上面是否正确添加了 ip route 路由规则。
#!/bin/bash

# ==========================================
# 1. 基础配置参数 (请根据实际情况修改)
# ==========================================
UBUNTU_PUB_IP="11.22.33.44"            # Ubuntu的公网固定IP
MIKROTIK_DDNS="yourname.sn.mynetname.net" # 【请修改】MikroTik的DDNS域名
IPSEC_PSK="YourSuperSecretKey"            # 【请修改】IPsec的预共享密钥

TUNNEL_UBUNTU_IP="10.100.100.2"            # IPIP隧道 Ubuntu端的内网IP
TUNNEL_MIKROTIK_IP="10.100.100.1"          # IPIP隧道 MikroTik端的内网IP

# 【新增】MikroTik的内网网段 (无需在ROS做NAT,Ubuntu会代为NAT并配置回程路由)
# 支持多个网段,用空格分隔。例如:"192.168.88.0/24 10.10.10.0/24"
MIKROTIK_LAN_SUBNETS="10.0.0.0/8" 

# 自动获取主网卡名称 (用于NAT代理上网)
MAIN_INTERFACE=$(ip route | grep default | awk '{print $5}' | head -n 1)

# ==========================================
# 前置检查
# ==========================================
if [ "$EUID" -ne 0 ]; then
  echo "请使用 root 权限运行此脚本 (例如: sudo $0)"
  exit 1
fi

if [ -z "$MAIN_INTERFACE" ]; then
  echo "错误: 无法获取默认外网网卡!"
  exit 1
fi

# ==========================================
# 功能模块
# ==========================================

function do_install() {
    echo ">>> [1/5] 更新并安装必要的软件包..."
    apt-get update
    apt-get install -y strongswan strongswan-pki libcharon-extra-plugins dnsutils iptables

    echo ">>> [2/5] 配置 IPsec (strongSwan) 兼容 MikroTik..."
    cat > /etc/ipsec.secrets <<EOF
$UBUNTU_PUB_IP %any : PSK "$IPSEC_PSK"
EOF

    cat > /etc/ipsec.conf <<EOF
config setup
    charondebug="ike 1, knl 1, cfg 0"
    uniqueids=no

conn ipip-tunnel
    authby=secret
    type=transport
    keyexchange=ikev1
    left=$UBUNTU_PUB_IP
    leftprotoport=4
    right=%any
    rightprotoport=4
    ike=aes256-sha256-modp2048,aes128-sha1-modp1024,aes256-sha1-modp1024!
    esp=aes256-sha256-modp2048,aes128-sha1-modp1024,aes256-sha1-modp1024,aes128-sha1,aes256-sha1!
    auto=add
    dpdaction=clear
    dpddelay=30s
EOF

    echo ">>> [3/5] 配置系统 IPv4 转发..."
    sed -i '/net.ipv4.ip_forward/s/^#//g' /etc/sysctl.conf
    grep -q "net.ipv4.ip_forward = 1" /etc/sysctl.conf || echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
    sysctl -p >/dev/null

    echo ">>> [4/5] 生成 带主动唤醒、心跳机制及回程路由 的 DDNS 守护进程..."
    cat > /usr/local/bin/ipip-ddns-daemon.sh <<EOF
#!/bin/bash
CURRENT_IP=""

# 确保 NAT 规则存在 (允许隧道IP和MikroTik内网网段通过Ubuntu上网)
SUBNETS="${TUNNEL_MIKROTIK_IP}/32 ${MIKROTIK_LAN_SUBNETS}"
for subnet in $SUBNETS; do
    iptables -t nat -C POSTROUTING -s $subnet -o $MAIN_INTERFACE -j MASQUERADE 2>/dev/null || \
    iptables -t nat -A POSTROUTING -s $subnet -o $MAIN_INTERFACE -j MASQUERADE
done

while true; do
    # 解析 DDNS 获取远端动态 IP
    NEW_IP=$(dig +short $MIKROTIK_DDNS | grep -E '^[0-9]+.[0-9]+.[0-9]+.[0-9]+$' | tail -n1)
    
    if [ -n "$NEW_IP" ]; then
        if [ "$NEW_IP" != "$CURRENT_IP" ]; then
            echo "$(date): MikroTik IP 变更为 '$NEW_IP'. 更新隧道..."
            
            # 删除旧隧道
            ip link set ipip0 down 2>/dev/null
            ip tunnel del ipip0 2>/dev/null
            
            # 建立新隧道
            ip tunnel add ipip0 mode ipip local $UBUNTU_PUB_IP remote $NEW_IP
            ip link set ipip0 up
            ip addr add $TUNNEL_UBUNTU_IP peer $TUNNEL_MIKROTIK_IP dev ipip0
            
            # 【新增】添加 MikroTik 内网网段的回程路由
            for subnet in ${MIKROTIK_LAN_SUBNETS}; do
                ip route replace $subnet via $TUNNEL_MIKROTIK_IP dev ipip0
                echo "$(date): 已添加回程路由: $subnet -> $TUNNEL_MIKROTIK_IP"
            done
            
            CURRENT_IP=$NEW_IP
            
            # 重载 IPsec 触发重新协商
            ipsec restart >/dev/null 2>&1
            
            # 【主动唤醒】:等待IPsec服务就绪后,强制发送流量唤醒通道
            sleep 3
            echo "$(date): 正在主动唤醒 IPsec 通道..."
            ping -c 3 -W 1 $TUNNEL_MIKROTIK_IP >/dev/null 2>&1
            
        else
            # 【心跳保活 Keepalive】:IP没变时,持续发送静默Ping包保持连接活跃
            ping -c 1 -W 1 $TUNNEL_MIKROTIK_IP >/dev/null 2>&1
        fi
    fi
    # 缩短循环时间至 15 秒,加快断线重连速度与心跳频率
    sleep 15
done
EOF
    chmod +x /usr/local/bin/ipip-ddns-daemon.sh

    echo ">>> [5/5] 配置 Systemd 服务..."
    cat > /etc/systemd/system/ipip-tunnel.service <<EOF
[Unit]
Description=Dynamic IPIP Tunnel Daemon
After=network.target strongswan-starter.service

[Service]
Type=simple
ExecStart=/usr/local/bin/ipip-ddns-daemon.sh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable ipip-tunnel.service
    do_start
    echo "======================================"
    echo "安装并启动完成!已启用 主动唤醒 与 心跳保活 功能。"
    echo "你可以使用 $0 status 查看运行状态。"
    echo "======================================"
}

function do_start() {
    echo "正在启动 IPsec 和 IPIP 隧道服务..."
    ipsec restart >/dev/null 2>&1
    systemctl start ipip-tunnel.service
    echo "已启动。"
}

function do_stop() {
    echo "正在停止 IPIP 隧道服务..."
    systemctl stop ipip-tunnel.service
    ipsec stop >/dev/null 2>&1
    
    echo "清理网卡接口和 NAT 规则..."
    # 删除网卡时,内核会自动清理挂在它上面的静态路由,所以无需手动删路由
    ip link set ipip0 down 2>/dev/null
    ip tunnel del ipip0 2>/dev/null
    
    # 清理防火墙 NAT 规则
    SUBNETS="${TUNNEL_MIKROTIK_IP}/32 ${MIKROTIK_LAN_SUBNETS}"
    for subnet in $SUBNETS; do
        iptables -t nat -D POSTROUTING -s $subnet -o $MAIN_INTERFACE -j MASQUERADE 2>/dev/null
    done
    echo "已停止。"
}

function do_restart() {
    do_stop
    sleep 2
    do_start
}

function do_status() {
    echo "================ Systemd 守护进程状态 ================"
    systemctl status ipip-tunnel.service --no-pager
    echo ""
    echo "================ IPsec 通道状态 ======================"
    ipsec status
    echo ""
    echo "================ 网卡接口状态 ========================"
    ip a show ipip0 2>/dev/null || echo "ipip0 接口未创建"
    echo ""
    echo "================ 路由表状态 ========================"
    ip route | grep ipip0 || echo "暂无指向 ipip0 的路由"
}

function do_uninstall() {
    read -p "确定要彻底卸载并清理配置吗?(y/n): " confirm
    if [ "$confirm" != "y" ]; then
        echo "已取消卸载。"
        exit 0
    fi
    
    do_stop
    echo "正在移除配置和脚本..."
    systemctl disable ipip-tunnel.service 2>/dev/null
    rm -f /etc/systemd/system/ipip-tunnel.service
    rm -f /usr/local/bin/ipip-ddns-daemon.sh
    systemctl daemon-reload
    
    rm -f /etc/ipsec.conf
    rm -f /etc/ipsec.secrets
    
    echo "卸载完成!如果不再需要 IPsec,可手动运行: apt purge strongswan"
}

# ==========================================
# 命令行参数解析
# ==========================================
case "$1" in
    install)
        do_install
        ;;
    start)
        do_start
        ;;
    stop)
        do_stop
        ;;
    restart)
        do_restart
        ;;
    status)
        do_status
        ;;
    uninstall)
        do_uninstall
        ;;
    *)
        echo "使用方法: $0 {install|start|stop|restart|status|uninstall}"
        echo ""
        echo "   install   - 覆盖配置并安装/启动服务"
        echo "   start     - 启动隧道和守护进程"
        echo "   stop      - 停止隧道、守护进程,并清理网络接口"
        echo "   restart   - 重启服务"
        echo "   status    - 查看服务运行状态、IPsec状态"
        echo "   uninstall - 彻底停止服务并清理所有的配置文件"
        exit 1
        ;;
esac
发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注