背景
内网防火墙接了多家宽带,故而主机也分配了多个 IPv6 地址,正常情况下防火墙默认线路是哪一条线路,主机默认使用的 IPv6 地址也是这条线路的。
但是,有时候我们需要使用移动 IPv6 来测试网络质量,有时候又需要电信,那么在不改防火墙配置的情况下有没有办法指定使用哪个 IPv6 地址呢?这是肯定的。
思路
Linux
Linux 环境下,我们可以利用 iptables
的 SNAT
功能,SNAT
即 Source Network Address Translation,源网络地址转换。内部地址要访问公网上的服务时,内部地址会主动发起连接,将内部地址转换为公网 IP,有关这个地址转换称为 SNAT。
Windows
Windows 环境下,也有 Linux 的 SNAT
相关功能,不过配置相对复杂,我们可以直接使用临时删除 IP 的方式来实现指定出站 IP。
方法
Linux
脚本
#!/bin/bash echo -e '\n------------------------------\n' #################### 指定 IPv6 运营商 #################### #电信 ct、移动 cm、联通 cu if [ ! -n "$1" ]; then echo -e '您未指定出口营运商前缀\n(电信:\033[36m ip6default.sh ct \033[0m;移动:\033[36m ip6default.sh cm \033[0m;联通:\033[36m ip6default.sh cu \033[0m)' t="default" elif [ "${1}" == "ct" ]; then echo -e '指定营运商为:\033[36m 电信(240e) \033[0m' t="240e" elif [ "${1}" == "cm" ]; then echo -e '指定营运商为:\033[36m 移动(2409) \033[0m' t="2409" elif [ "${1}" == "cu" ]; then echo -e '指定营运商为:\033[36m 联通(2408) \033[0m' t="2408" else echo -e '\033[31m指定前缀不支持,退出脚本 \033[0m\n' exit 0 fi ###################### 获取网卡名称 ###################### check_net(){ echo -e '\n------------------------------\n' echo -e "检测启用 IPv6 的网卡 ...\n" network=$(ifconfig |awk '{print $1}'|grep :|awk -F: '{print $1}') for net_name in ${network} do if [ ${net_name} = "lo" ]; then continue fi running_num=$(ifconfig ${net_name}|grep RUNNING|wc -l) if [ ${running_num} -ge 1 ]; then ips=$(ip addr show ${net_name} | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}') for aip in ${ips} do if [ "${aip}" != "${aip#*:[0-9a-fA-F]}" ]; then preffix=$(echo ${aip} | tr ":" "\n" | head -n 1) if [ "${preffix}" == "${t}" ]; then echo -e "网卡\033[33m "${net_name}" \033[0m检测到匹配的 IPv6 地址:\033[33m "${aip}"\033[0m" choose_net=${net_name} choose_ip=${aip} break fi fi done else echo -e "网卡 "${net_name}" 已被禁用" fi done #ename=$(ifconfig |grep 4163|tr ":" "\n"|head -n 1) #ename="ens32" if [ ${choose_net} ]; then ename=${choose_net} echo -e '\n选定网卡接口名称:\033[33m '${ename}'\033[0m' else echo -e "\n所有网卡均未分配指定运营商 IPv6,退出脚本\n" exit 1 fi } ##################### 启/禁用 IPv6 ###################### enable_ipv6(){ flag_ipv6=$(cat /proc/sys/net/ipv6/conf/${ename}/disable_ipv6) if [ "${1}" ]; then echo -e '------------------------------\n' echo -e '启用/禁用接口 IPv6 功能 ...' if [[ ${1} -eq "1" && ${flag_ipv6} -eq "0" ]]; then echo 0 > /proc/sys/net/ipv6/conf/${ename}/disable_ipv6 echo -e '\n\033[32m已启用\033[0m' elif [[ ${1} -eq "0" && ${flag_ipv6} -eq "1" ]]; then echo -e '\n\033[32m已禁用\033[0m' echo 1 > /proc/sys/net/ipv6/conf/${ename}/disable_ipv6 else echo -e '\n\033[32m无需操作\033[0m' fi else echo -e "\n未指定操作" fi } #################### 添加 NAT 规则 #################### add_nat(){ if [ ${1} == "1" ]; then echo -e '添加规则中 ...' add_nat=$(ip6tables -t nat -I POSTROUTING -o ${2} -d ::/0 -j SNAT --to-source ${3}) add_cnt=$(ip6tables -t nat -vnL POSTROUTING --line-number | wc -l) if [ ${add_cnt} -eq 3 ]; then ipv6rules=$(ip6tables -t nat -vnL POSTROUTING --line-number | sed -n "3,3p" | awk '{str="接口:"$7",来源:"$8",目标:"$9",指定出口:"$10; printf str}' | awk 'BEGIN{FS="to:"}{printf $1}{printf $2}') echo -e "\n添加成功,NAT 规则为:\n\033[32m${ipv6rules}\033[0m\n" nat_tip="1" else echo -e '\n规则\033[32m添加失败\033[0m,可尝试手动执行命令:' do_nat ${1} ${2} ${3} fi fi } #################### NAT 操作命令 #################### do_nat(){ echo -e '查询 NAT 规则:(\033[36m ip6tables -t nat -vnL POSTROUTING --line-number\033[0m)' echo -e '删除 NAT 规则:(\033[36m ip6tables -t nat -F POSTROUTING\033[0m)' echo -e '添加 NAT 规则:(\033[36m ip6tables -t nat -I POSTROUTING -o '${2}' -d ::/0 -j SNAT --to-source '${3}'\033[0m)\n' } #################### 检测生效的 NAT #################### check_nat(){ echo -e '\n------------------------------\n' echo -e '检测防火墙 NAT 规则 ...\n' rule_cnt=$(ip6tables -t nat -vnL POSTROUTING --line-number | wc -l) if [ ${rule_cnt} -le 2 ]; then echo -e '\033[32m未检测到生效的规则\033[0m\n' add_nat ${1} ${2} ${3} else if [ ${rule_cnt} -eq 3 ]; then ipv6rules=$(ip6tables -t nat -vnL POSTROUTING --line-number | sed -n "3,3p" | awk '{str="接口:"$7",来源:"$8",目标:"$9",指定出口:"$10; printf str}' | awk 'BEGIN{FS="to:"}{printf $1}{printf $2}') echo -e "NAT 规则为:\n\033[32m${ipv6rules}\033[0m" if [ -n "${3}" ]; then ipv6nat=$(ip6tables -t nat -vnL POSTROUTING --line-number | sed -n "3,3p" | awk '{printf $10}' | awk 'BEGIN{FS="to:"}{printf $2}') if [ "${ipv6nat}" != "${3}" ]; then echo -e "\n与已生效的 NAT 规则冲突,删除原规则 ..." del_rule=$(ip6tables -t nat -F POSTROUTING) rule_cnt=$(ip6tables -t nat -vnL POSTROUTING --line-number | wc -l) if [ ${rule_cnt} -le 2 ]; then echo -e '\033[32m\n删除成功\033[0m,尝试添加新规则 ...\n' add_nat ${1} ${2} ${3} fi else nat_tip="1" fi else nat_tip="1" fi else echo -e "\n检测到有多条生效规则,请手动执行命令:" do_nat ${1} ${2} ${3} echo -e '\n------------------------------\n' exit 1 fi if [ "${nat_tip}" == "1" ]; then echo -e "\n可手动执行命令查看:\033[36m ip6tables -t nat -vnL POSTROUTING --line-number\033[0m\n" fi fi } #################### 检测生效的 IPv6 #################### check(){ echo -e '------------------------------\n' echo -e '检测已生效的 IP 地址 ...' ip6=$(curl -s -6 -X GET http://ipv6.lookup.test-ipv6.com | jq -r '(.ip)') if [[ ${ip6} == *"Couldn't connect to server"* ]]; then echo -e '\n未检测到生效的 IPv6 地址,退出脚本' exit 1 elif [ ! "${ip6}" ]; then echo -e "\n\033[32m检测接口未响应数据,更换接口 ...\033[0m" ip6=$(curl -s -6 -X GET http://test6.ustc.edu.cn/backend/getIP.php | jq -r '(.processedString)') if [ ! "${ip6}" ]; then echo -e "\033[32m新检测接口未响应数据,再次更换接口 ...\033[0m" ip6=$(wget -q -O - http://speed.neu6.edu.cn/getIP.php) if [ ! "${ip6}" ]; then echo -e "\033[32m多次尝试仍未取得响应数据,退出脚本\033[0m" echo -e "\n可尝试手动执行命令:\033[36m curl -s -6 -X GET http://test6.ustc.edu.cn/backend/getIP.php | jq -r '(.processedString)'\033[0m\n" exit 1 fi fi fi echo -e '\n检测到 IP 信息如下:' echo -e '\033[32mIP 地址:'${ip6}'\033[0m' info=$(curl -s -6 -X GET -A 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36' https://api.ip.sb/geoip/${ip6} | jq -r '"\n运营商:\(.isp)\n位置:\(.region),\(.country)"') echo -e '\033[32m'${info}'\033[0m\n' ipv6=$(echo ${ip6} | tr ":" "\n" | head -n 1) if [ ! -n "${ipv6}" ]; then echo -e '\033[31m未检测到 IPv6 地址,退出脚本 \033[0m\n' exit 1 elif [ "${ipv6}" == "240e" ]; then echo -e '生效的 IPv6 运营商是:\033[32m 电信(240e) \033[0m' elif [ "${ipv6}" == "2409" ]; then echo -e '生效的 IPv6 运营商是:\033[32m 移动(2409) \033[0m' elif [ "${ipv6}" == "2408" ]; then echo -e '生效的 IPv6 运营商是:\033[32m 联通(2408) \033[0m' fi ipv6_nat=$(ip6tables -t nat -vnL POSTROUTING --line-number | sed -n "3,3p" | awk '{printf $10}' | awk 'BEGIN{FS="to:"}{printf $2}') prefix=$(echo ${ipv6_nat} | tr ":" "\n" | head -n 1) if [ "${ipv6}" == "${prefix}" ]; then echo -e '\033[32m与 NAT 规则一致 \033[0m' else echo -e '\033[31m与 NAT 规则不一致 \033[0m' fi if [ "${1}" ]; then if [ "${ipv6}" == "${1}" ]; then echo -e '\n\033[32m指定运营商执行成功!\033[0m' echo -e '\n\033[31m注意若 IPv6 地址发生变更,或者重启,需重新执行本脚本\033[0m\n' else echo -e '\n\033[31m指定运营商执行失败!\033[0m' echo -e '\n\033[31m生效的运营商与指定的运营商不是同一家,请重新执行本脚本\033[0m\n' fi fi } if [ "${t}" == "default" ]; then check_nat 0 check echo -e '\n------------------------------\n' else #################### 设置指定的 IPv6 #################### echo -e 'IPv6 前缀为:\033[33m '${t}' \033[0m' check_net if [ ${choose_ip} ]; then ip6=${choose_ip} else ip6=$(ifconfig | grep ${t} | tr " " "\n" | grep ${t} | head -n 1) fi if [ ! -n "${ip6}" ]; then echo -e '\n\033[31m'${ename}'该接口无匹配 IPv6\033[0m' enable_ipv6 0 echo -e '如需重新启用 IPv6 请手动执行命令:\033[36m echo 0 > /proc/sys/net/ipv6/conf/'${ename}'/disable_ipv6\033[0m' exit 0 else echo -e '选定的出口 IPv6:\033[33m '${ip6}' \033[0m' check_nat 1 ${ename} ${ip6} check ${t} fi fi
Sh
用法
本脚本支持指定电信、联通、移动三家运营商的 IPv6 地址,使用时执行:
root@ct:~/bash# ./ip6default.sh ct
Sh
其中 ct
指电信,cu
指联通,cm
指移动,若不指定,则默认检查当前系统生效的 IPv6 地址。
本脚本可自动识别网卡,也适用于多网卡环境。
本脚本使用 jq
命令,若未安装请先安装。
Windows
命令
::功能:指定出口 IPv6 地址 ::用法:直接执行本脚本 ::参数:参数 1:ct/cu/cm,用于指定运营商 :: 参数 2:y/n,用于确认是否重新获取地址 :: 参数 3:y/n,用于确认是否重新检测地址 ::场景:网卡分配了多个 IPv6 地址,则使用本脚本可指定出口 IPv6 地址 ::说明:若未输入参数,则需要在执行过程中输入 ::原理:先通过重置网卡重新获取 IP 地址,然后通过删除不需要的 IPv6 地址来实现指定 ::依赖:需安装 GNU 下的 curl、grep、awk、wget 命令 @echo off title 指定出口 IPv6 地址 echo ------------------------------ echo ------- 指定出口 IPv6 地址------ echo ------------------------------ echo. set type=%1 set reset=%2 set again=%3 if [%type%]==[] ( SET /P type=请输入指定 IPv6 编号地址(ct/cu/cm): ) if "%type%"=="ct" ( echo 您选择的是:电信(ct) set suffix=240e ) else if "%type%"=="cu" ( echo 您选择的是:联通(cu) set suffix=2408 ) else if "%type%"=="cm" ( echo 您选择的是:移动(cm) set suffix=2409 ) else ( echo 选择不正确,自动退出 goto end ) echo. if [%reset%]==[] ( if [%1]==[] ( SET /P reset=是否重新获取 IP 地址(y/n): ) ) if "%reset%"=="y" ( echo 您选择的是:重新获取(y) ) else ( echo 您选择的是:不重新获取(n) ) echo. echo ------------------------------ echo. echo 检测生效的网卡 ... echo. echo. FOR /F "tokens=5*" %%i in ('netsh interface ip show interfaces ^| more +3 ^| grep -v "disconnected" ^| grep -v "Loopback"') DO ( set netname=%%i echo 检测到网卡名为:%%i echo. goto setipv6 ) ::重新获取 IP :resetnetwork if "%reset%"=="y" ( echo ------------------------------ echo. echo 更新本机 IP 地址 ... :: netsh interface set interface "%netname%" disabled :: netsh interface set interface "%netname%" enabled ipconfig /renew "%netname%" :: timeout /nobreak /t 8 echo 更新完成 echo. ) ::设置出口 IP :setipv6 echo 检测 %netname% 分配的 IPv6 地址 ... :: FOR /F "tokens=15*" %%a in ('ipconfig ^| find "IPv6"') DO ( FOR /F %%a in ('netsh interface ipv6 show addresses %netname% ^| find "参数" ^| grep -v "fe80" ^| awk "{ print $2 }"') DO ( echo %%a | findstr %suffix% >NUL && ( echo %%a(匹配,正在设置指定) ) || ( if [%%a]==[] ( echo 未检测到,自动退出 goto end ) else ( FOR /F %%j in ('netsh interface ipv6 delete address interface="%netname%" address="%%a"') DO ( set selddrr=%%j ) ) ) ) echo. echo ------------------------------ echo. echo 设置完成,验证是否生效 ... echo. ::timeout /nobreak /t 5 echo. set ipaddr= set IPV6_REGEX="\(\([0-9A-Fa-f]\{1,4\}:\)\{1,\}\)\(\([0-9A-Fa-f]\{1,4\}\)\{0,1\}\)\(\(:[0-9A-Fa-f]\{1,4\}\)\{1,\}\)" FOR /F %%i in ('curl -6sL http://ip.sb ^| grep -m 1 -o %IPV6_REGEX%') DO ( set ipaddr=%%i ) if [%ipaddr%]==[] ( echo 检测接口未响应数据,更换接口 ... goto check ) else ( echo 检测到生效的地址是:%ipaddr% echo. echo 确认是否为指定 ... echo %ipaddr% | findstr %suffix% >NUL && ( echo 已确认,操作成功 ) || ( echo 非指定运营商 echo. if [%again%]==[] ( SET /P again=是否重新检测(y/n): ) if "%again%"=="y" ( echo 您已选择重新检测(y) echo 检测中 ... goto check ) else ( echo 取消检测,自动退出 goto end ) ) ) ::测试发现,多次运行会出现地址检测不准确的情况,所以再加一个是否重新检测 :check FOR /F %%j in ('curl -6sL http://v6.ipv6-test.com/api/myip.php ^| grep -m 1 -o %IPV6_REGEX%') DO ( set ipaddrr=%%j ) if [%ipaddrr%]==[] ( echo 检测接口未响应数据,更换接口 ... FOR /F %%l in ('wget -q -6 -O - http://speed.neu6.edu.cn/getIP.php') DO ( set ipaddrr=%%l ) if [%ipaddrr%]==[] ( echo 多次尝试仍未取得响应数据,退出脚本 goto end ) ) echo 检测到生效的 IPv6 地址是:%ipaddrr% echo. echo 确认是否为指定 ... echo %ipaddrr% | findstr %suffix% >NUL && ( echo 已确认,操作成功 ) || ( echo 非指定运营商,操作失败 goto end ) echo. :end echo. echo 路由跟踪确认一下: tracert -6 -h 5 www.qq.com echo. echo.
Cmd
用法
直接双击打开,根据提示输入即可。
注意,本脚本对多网卡支持度不好,后续再改善。
效果
Linux
Windows
推荐本站淘宝优惠价购买喜欢的宝贝:
本文链接:https://hqyman.cn/post/7748.html 非本站原创文章欢迎转载,原创文章需保留本站地址!
打赏
微信支付宝扫一扫,打赏作者吧~
休息一下~~