0. 前言
之前我们实现了在 vps 上的 IPv6 池代理, 现在弄一个更适合家宽的
1. systcl 配置
# /etc/sysctl.d/sysctl.conf net.ipv6.conf.default.forwarding=1 net.ipv6.conf.all.forwarding=1 net.ipv6.conf.all.proxy_ndp=1 net.ipv6.ip_nonlocal_bind=1 net.core.default_qdisc = cake net.ipv4.tcp_congestion_control = bbr net.ipv4.tcp_fastopen = 3
2. ndppd 配置
# /etc/ndppd
route-ttl 30000
proxy ens18 {
router yes
timeout 60
ttl 300
rule 240e:1234:5678:abcd::/64 {
static
}
}3. Xray 配置
这里需要修改 outbounds 里的 sendThrough
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"port": 10808,
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": true,
"ip": "127.0.0.1"
}
}
],
"outbounds": [
{
"tag": "ipv6-proxy-pool",
"protocol": "freedom",
"sendThrough": "240e:1234:5678:abcd::/64"
},
{
"tag": "blocked",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"outboundTag": "ipv6-proxy-pool",
"port": "1-65535"
}
]
}
}4. Systemd 配置, 实现动态切换
实现清除宽带重播后的旧 v6, 放在 /usr/local/bin/cleanup-deprecated-ipv6.sh
#!/bin/bash
while true; do
ip -6 addr | grep deprecated | awk '{print $2}' | cut -d'/' -f1 | while read addr; do
[ -n "$addr" ] && ip -6 addr del $addr/64 dev ens18
done
sleep 1
done# /etc/systemd/system/cleanup-deprecated-ipv6.service [Unit] Description=Auto cleanup deprecated IPv6 addresses After=network.target [Service] ExecStart=/usr/local/bin/cleanup-deprecated-ipv6.sh Restart=always [Install] WantedBy=multi-user.target
实现 v6 变动后, 路由, xray 以及 ndppd 的配置变更, 记得修改网卡, 脚本放在 /usr/local/bin/update-ipv6-prefix.sh
#!/bin/bash
set -e
DEV="ens18"
CONF="/etc/ndppd.conf"
XRAY_CONF="/usr/local/etc/xray/config.json"
LOG_FILE="/var/log/ipv6-prefix-update.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 更新 Xray 配置中的 sendThrough
update_xray_config() {
local new_prefix="$1"
if [ ! -f "$XRAY_CONF" ]; then
log "⚠️ Xray配置文件不存在: $XRAY_CONF"
return 1
fi
# 备份原配置
cp "$XRAY_CONF" "${XRAY_CONF}.bak"
# 使用 jq 更新 sendThrough 字段(如果系统有 jq)
if command -v jq &>/dev/null; then
jq --arg prefix "$new_prefix" \
'.outbounds |= map(if .tag == "ipv6-proxy-pool" then .sendThrough = $prefix else . end)' \
"$XRAY_CONF" > "${XRAY_CONF}.tmp" && mv "${XRAY_CONF}.tmp" "$XRAY_CONF"
log "✅ 使用 jq 更新 Xray 配置"
else
# 使用 sed 作为备选方案
sed -i -E "s|(\"sendThrough\":\s*\")[^\"]+(\")|\1${new_prefix}\2|g" "$XRAY_CONF"
log "✅ 使用 sed 更新 Xray 配置"
fi
# 重启 Xray 服务
if systemctl is-active --quiet xray; then
log "重启 Xray 服务..."
systemctl restart xray || log "⚠️ 无法重启 Xray,请检查服务状态。"
else
log "⚠️ Xray 服务未运行,跳过重启。"
fi
}
# 确保日志文件存在
mkdir -p "$(dirname "$LOG_FILE")"
touch "$LOG_FILE"
# 等待网络设备就绪
while ! ip link show dev "$DEV" &>/dev/null; do
log "等待网络接口 $DEV ..."
sleep 2
done
# 初始化时强制检查一次
FIRST_RUN=true
while true; do
# 获取接口的全局 IPv6 地址,排除 ULA (fd00::/8) 和链路本地地址 (fe80::/10)
FULL_ADDR=$(ip -6 addr show dev $DEV scope global 2>/dev/null | \
grep -oP '([0-9a-f:]+)/64' | \
grep -v '^fd[0-9a-f][0-9a-f]:' | \
grep -v '^fe[89ab][0-9a-f]:' | \
head -n1 | \
cut -d'/' -f1)
if [ -z "$FULL_ADDR" ]; then
sleep 2
continue
fi
NEW_PREFIX=$(echo "$FULL_ADDR" | awk -F: '{print $1":"$2":"$3":"$4"::/64"}')
OLD_PREFIX=$(grep -oP 'rule\s+\K[0-9a-f:]+::/64' "$CONF" 2>/dev/null | head -n1)
# 第一次运行或前缀变化时触发
if [ "$FIRST_RUN" = true ] || [ "$OLD_PREFIX" != "$NEW_PREFIX" ]; then
log "检测到IPv6前缀更新:${OLD_PREFIX:-<none>} → $NEW_PREFIX"
# 删除旧路由
if [ -n "$OLD_PREFIX" ]; then
log "删除旧路由: $OLD_PREFIX"
ip -6 route del local "$OLD_PREFIX" dev "$DEV" 2>/dev/null || true
fi
# 添加新路由
log "添加新路由: $NEW_PREFIX"
ip -6 route add local "$NEW_PREFIX" dev "$DEV" 2>/dev/null || true
# 更新 ndppd.conf
if [ -n "$OLD_PREFIX" ]; then
sed -i "s|$OLD_PREFIX|$NEW_PREFIX|g" "$CONF"
else
log "插入新的 rule 段到 ndppd.conf"
sed -i "/proxy $DEV {/a\ rule $NEW_PREFIX {\n static\n iface $DEV\n }" "$CONF"
fi
# 重启 ndppd
log "重启 ndppd..."
systemctl restart ndppd || log "⚠️ 无法重启 ndppd,请检查 systemd 服务状态。"
# 更新 Xray 配置
log "更新 Xray 配置..."
update_xray_config "$NEW_PREFIX"
log "✅ IPv6 前缀更新完成: $NEW_PREFIX"
FIRST_RUN=false
fi
sleep 3
done# /etc/systemd/system/update-ipv6-prefix.service [Unit] Description=IPv6 Prefix Monitor Service After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/update-ipv6-prefix.sh Restart=always RestartSec=3 User=root # 安全加固(可选) StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
5. 食用方法
package main
import (
"fmt"
"github.com/imroc/req/v3"
"time"
)
func main() {
client := req.C().SetProxyURL("http://127.0.0.1:10808")
ticker := time.NewTicker(time.Second)
for range ticker.C {
resp, err := client.R().
Get("http://api.bilibili.com/x/web-interface/zone")
if err != nil {
panic(err)
}
fmt.Println(resp.String())
}
}
0 条评论