-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaddipv6.sh
More file actions
256 lines (224 loc) · 9.16 KB
/
Copy pathaddipv6.sh
File metadata and controls
256 lines (224 loc) · 9.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#!/bin/bash
echo "====================================="
echo "欢迎使用 ADD IPv6 管理工具"
echo "作者: Calvin"
echo "提醒: 合理使用"
echo "====================================="
# 1. 必须以 root 权限执行
if [ "$(id -u)" -ne 0 ]; then
echo "请以root权限执行此脚本。"
exit 1
fi
# 2. 用来选择具有全局 IPv6 的网卡
function choose_interface() {
GLOBAL_IPV6_INTERFACES=()
for iface in $(ip -o link show | awk -F': ' '{print $2}'); do
if ip -6 addr show dev "$iface" scope global | grep -q 'inet6'; then
GLOBAL_IPV6_INTERFACES+=("$iface")
fi
done
if [ ${#GLOBAL_IPV6_INTERFACES[@]} -eq 0 ]; then
echo "未检测到具有全局 IPv6 地址的网卡,请检查VPS的网络配置。"
exit 1
fi
if [ ${#GLOBAL_IPV6_INTERFACES[@]} -eq 1 ]; then
SELECTED_IFACE="${GLOBAL_IPV6_INTERFACES[0]}"
else
echo "检测到以下具有全局 IPv6 地址的网卡:"
for i in "${!GLOBAL_IPV6_INTERFACES[@]}"; do
echo "$((i+1)). ${GLOBAL_IPV6_INTERFACES[$i]}"
done
read -p "请选择要使用的网卡编号: " choice
if ! [[ "$choice" =~ ^[1-9][0-9]*$ ]] || [ "$choice" -gt "${#GLOBAL_IPV6_INTERFACES[@]}" ]; then
echo "选择无效。"
exit 1
fi
SELECTED_IFACE="${GLOBAL_IPV6_INTERFACES[$((choice-1))]}"
fi
echo "选择的网卡为:$SELECTED_IFACE"
}
# 3. 添加随机 IPv6 地址函数
function add_random_ipv6() {
# 检查 python3 依赖
if ! command -v python3 &> /dev/null; then
echo "本功能需要 python3 来随机生成 IPv6 地址,请先安装 python3 后再试。"
exit 1
fi
choose_interface
# 获取网卡上任意一个全局 IPv6 地址(含CIDR)
ipv6_cidr=$(ip -6 addr show dev "$SELECTED_IFACE" scope global | awk '/inet6/ {print $2}' | head -n1)
if [ -z "$ipv6_cidr" ]; then
echo "无法获取 $SELECTED_IFACE 的全局 IPv6 地址。"
exit 1
fi
BASE_ADDR=$(echo "$ipv6_cidr" | cut -d'/' -f1)
PLEN=$(echo "$ipv6_cidr" | cut -d'/' -f2)
echo "检测到 IPv6 地址: $ipv6_cidr"
echo "使用的网络: $BASE_ADDR/$PLEN"
# 如果是 /128,就无法再随机生成其他地址
if [ "$PLEN" -eq 128 ]; then
echo "检测到前缀为 /128,不支持随机生成其它地址。"
exit 1
fi
read -p "请输入要添加的随机 IPv6 地址数量: " COUNT
if ! [[ "$COUNT" =~ ^[0-9]+$ ]]; then
echo "数量必须为整数。"
exit 1
fi
# 执行循环随机添加
for (( i=1; i<=COUNT; i++ )); do
RANDOM_ADDR=$(python3 -c "import ipaddress, random; \
net=ipaddress.ip_network('$BASE_ADDR/$PLEN', strict=False); \
print(ipaddress.IPv6Address(random.randint(int(net.network_address), int(net.broadcast_address))))")
echo "添加地址: ${RANDOM_ADDR}/${PLEN}"
ip -6 addr add "${RANDOM_ADDR}/${PLEN}" dev "$SELECTED_IFACE"
if [ $? -eq 0 ]; then
# 记录添加成功的地址
echo "${RANDOM_ADDR}/${PLEN}" >> /tmp/added_v6_ipv6.txt
else
echo "添加 ${RANDOM_ADDR}/${PLEN} 失败,请检查系统日志或网络配置。"
fi
done
echo "所有随机地址添加完成。"
}
# 4. 管理默认出口 IPv6 地址
function manage_default_ipv6() {
choose_interface
# 列出所有全局 IPv6 地址
echo "检测到以下IPv6地址(全局范围):"
mapfile -t ipv6_list < <(ip -6 addr show dev "$SELECTED_IFACE" scope global | awk '/inet6/ {print $2}')
if [ ${#ipv6_list[@]} -eq 0 ]; then
echo "网卡 $SELECTED_IFACE 上未检测到全局IPv6地址。"
exit 1
fi
for i in "${!ipv6_list[@]}"; do
echo "$((i+1)). ${ipv6_list[$i]}"
done
read -p "请输入要设置为出口的IPv6地址对应的序号: " addr_choice
if ! [[ "$addr_choice" =~ ^[0-9]+$ ]] || [ "$addr_choice" -gt "${#ipv6_list[@]}" ] || [ "$addr_choice" -lt 1 ]; then
echo "选择无效。"
exit 1
fi
# 拿到选中的地址(去掉 /前缀长度)
SELECTED_ENTRY="${ipv6_list[$((addr_choice-1))]}"
SELECTED_IP=$(echo "$SELECTED_ENTRY" | cut -d'/' -f1)
echo "选择的默认出口IPv6地址为:$SELECTED_IP"
# 尝试检测默认网关
GATEWAY=$(ip -6 route show default dev "$SELECTED_IFACE" | awk '/default/ {print $3}' | head -n1)
# 如果没有 default dev XXX,再去找所有 dev XXX 下的 via
if [ -z "$GATEWAY" ]; then
GATEWAY=$(ip -6 route show dev "$SELECTED_IFACE" | awk '/via/ {print $3}' | head -n1)
fi
if [ -z "$GATEWAY" ]; then
echo "未检测到默认IPv6网关,请检查系统路由配置。"
exit 1
fi
echo "检测到默认IPv6网关为:$GATEWAY"
# 优先尝试 'add default';若已存在,改用 'change default'
ip -6 route add default via "$GATEWAY" dev "$SELECTED_IFACE" src "$SELECTED_IP" onlink 2>/tmp/ip6_err.log || \
ip -6 route change default via "$GATEWAY" dev "$SELECTED_IFACE" src "$SELECTED_IP" onlink 2>>/tmp/ip6_err.log
if [ $? -eq 0 ]; then
echo "默认出口IPv6地址更新成功,出站流量将使用 $SELECTED_IP 作为源地址。"
else
echo "更新默认出口IPv6地址失败,请检查系统路由配置(错误详情可查看 /tmp/ip6_err.log)。"
fi
# 询问是否持久化到 /etc/rc.local
read -p "是否将此配置写入 /etc/rc.local 以避免重启后失效?(y/n): " persist_choice
if [[ "$persist_choice" =~ ^[Yy]$ ]]; then
if [ ! -f /etc/rc.local ]; then
echo "#!/bin/bash" > /etc/rc.local
chmod +x /etc/rc.local
fi
# 避免重复追加
local_cmd="ip -6 route add default via \"$GATEWAY\" dev \"$SELECTED_IFACE\" src \"$SELECTED_IP\" onlink"
if ! grep -Fxq "$local_cmd" /etc/rc.local; then
echo "$local_cmd" >> /etc/rc.local
echo "配置已写入 /etc/rc.local 。"
else
echo "检测到 /etc/rc.local 中已存在相同配置,无需重复写入。"
fi
fi
}
# 5. 一键删除脚本添加过的所有 IPv6 地址
function delete_all_ipv6() {
choose_interface
if [ ! -f /tmp/added_v6_ipv6.txt ]; then
echo "未检测到 /tmp/added_v6_ipv6.txt 文件,说明没有记录或已被删除。"
exit 1
fi
while read -r entry; do
if [ -n "$entry" ]; then
echo "删除地址: $entry"
ip -6 addr del "$entry" dev "$SELECTED_IFACE"
fi
done < /tmp/added_v6_ipv6.txt
rm -f /tmp/added_v6_ipv6.txt
echo "所有添加的IPv6地址已删除。"
}
# 6. 只保留当前默认出口IPv6地址,删除其它所有
function delete_except_default_ipv6() {
choose_interface
# 获取当前默认路由的源地址
default_ip=$(ip -6 route show default dev "$SELECTED_IFACE" | \
awk '{for(i=1;i<=NF;i++){if($i=="src"){print $(i+1); exit}}}')
if [ -z "$default_ip" ]; then
echo "未检测到默认出口IPv6地址,请先设置默认出口IPv6地址后再执行。"
exit 1
fi
echo "当前默认出口IPv6地址: $default_ip"
# 遍历所有全局IPv6地址,删除与默认出口地址不同的
mapfile -t ip_entries < <(ip -6 addr show dev "$SELECTED_IFACE" scope global | awk '/inet6/ {print $2}')
for entry in "${ip_entries[@]}"; do
addr_only=$(echo "$entry" | cut -d'/' -f1)
if [ "$addr_only" != "$default_ip" ]; then
echo "删除地址: $entry"
ip -6 addr del "$entry" dev "$SELECTED_IFACE"
fi
done
echo "只保留默认出口IPv6地址 $default_ip,其它已删除。"
# 询问是否将当前配置写入 /etc/rc.local
read -p "是否将当前配置写入 /etc/rc.local 以避免重启后失效?(y/n): " persist_choice
if [[ "$persist_choice" =~ ^[Yy]$ ]]; then
gateway=$(ip -6 route show default dev "$SELECTED_IFACE" | awk '/default/ {print $3}' | head -n1)
if [ -z "$gateway" ]; then
echo "未检测到默认IPv6网关,无法写入配置。"
else
if [ ! -f /etc/rc.local ]; then
echo "#!/bin/bash" > /etc/rc.local
chmod +x /etc/rc.local
fi
local_cmd="ip -6 route add default via \"$gateway\" dev \"$SELECTED_IFACE\" src \"$default_ip\" onlink"
if ! grep -Fxq "$local_cmd" /etc/rc.local; then
echo "$local_cmd" >> /etc/rc.local
echo "配置已写入 /etc/rc.local 。"
else
echo "/etc/rc.local 中已存在相同配置,无需重复写入。"
fi
fi
fi
}
# 7. 主菜单
echo "请选择功能:"
echo "1. 添加随机 IPv6 地址"
echo "2. 管理默认出口 IPv6 地址"
echo "3. 一键删除全部添加的IPv6地址"
echo "4. 只保留当前出口默认的IPv6地址 (删除其它全部)"
read -p "请输入选择 (1, 2, 3 或 4): " choice_option
case "$choice_option" in
1)
add_random_ipv6
;;
2)
manage_default_ipv6
;;
3)
delete_all_ipv6
;;
4)
delete_except_default_ipv6
;;
*)
echo "无效的选择。"
exit 1
;;
esac