AI摘要:

文章介绍了在家庭网络中完成光猫改桥接后,将路由器改为padavan固件的K2P,并通过路由器直接拨号实现所有终端获得公网IPv6地址。使用aliddns6将动态公网IPv6指向固定域名,通过nextcloud NAS服务器的计划任务自动执行脚本实现自动更新。在校园网络中,由于使用校园无线网进行wisp无线桥接,无法直接为其下的终端分配IPv6,通过配置IPv6单独桥接解决。作者还分享了网络故障排除经历,包括更换路由器和刷机等操作。文章提供了详细的配置脚本和流程,并参考了相关教程和帖子。

家庭网络

此前已完成光猫改桥接工作,此次将路由器改为padavan固件的K2P,通过路由器直接拨号实测路由器下的所有终端均能获得公网ipv6地址,但为动态地址,设备重连网络后会重新分配新的公网ip。通过aliddns6即可将动态公网ipv6指向一个固定的域名,获取aliyun accesskey后填入如下脚本即可。家中的nextcloud NAS服务器建立计划任务每分钟自动执行一次脚本以实现自动更新。

#!/usr/bin/env bash

# Author: tyasky

ak=""
sk=""
host=""
domain=""

runnum=10              # 最多尝试更新次数
rungap=60              # 尝试间隔秒数
type=AAAA              # 解析记录类型
downvalue=""           # 解析值,留空则动态获取

cmdlist=(
    'curl --max-time 2 -s l2.io/ip'
    'curl --max-time 2 -s https://echoip.de'
    'curl --max-time 2 -s ifconfig.me'
    'curl --max-time 2 -s ipecho.net/plain'
    'curl --max-time 2 -s -L ident.me #API'
    'curl --max-time 2 -s -L tnx.nl/ip'
    'curl --max-time 2 -s wgetip.com'
    'curl --max-time 2 -s ip.tyk.nu'
    'curl --max-time 2 -s bot.whatismyipaddress.com'
    'curl --max-time 2 -s curlmyip.net'
    'curl --max-time 2 -s api.ipify.org'
    'curl --max-time 2 -s ipv4bot.whatismyipaddress.com'
    'curl --max-time 2 -s ipcalf.com'
    'ip -4 addr|grep global|head -1|awk -F/ "{print \$1}"|awk "{print \$NF}"'
    'ip -6 addr|grep global|head -1|awk -F/ "{print \$1}"|awk "{print \$NF}"'
)

# 第二个参数指定额外不编码的字符
# 笔记:[-_.~a-zA-Z0-9$2] 中的-字符用于表示区间,放到中间会出意外结果
urlencode() {
    local string="${1}"
    local strlen=${#string}
    local encoded=""
    local pos c o
    for pos in $(awk "BEGIN { for ( i=0; i<$strlen; i++ ) { print i; } }")
    do
        c=${string:$pos:1}
        case $c in
            [-_.~a-zA-Z0-9$2] ) o="${c}" ;;
            * ) o=`printf '%%%02X' "'$c"`
        esac
        encoded="$encoded$o"
    done
    echo "${encoded}"
}

send_request() {
    timestamp=`date -u +"%Y-%m-%dT%H:%M:%SZ"`
    # 服务器拒绝重放攻击(本次与前一次请求数据相同返回错误),SignatureNonce 需赋值随机数而不能是时间戳(可能同一秒两次请求)
    nonce=`openssl rand -base64 8 | md5sum | cut -c1-8`
    args="AccessKeyId=$ak&Format=json&SignatureMethod=HMAC-SHA1&SignatureNonce=$nonce&SignatureVersion=1.0&Timestamp=$timestamp&Version=2015-01-09&$1"
    # 签名要求参数按大小写敏感排序(sort 在本地语言环境可能会忽略大小写排序):LC_ALL=c sort
    args=`echo $args | sed 's/\&/\n/g' | LC_ALL=c sort | xargs | sed 's/ /\&/g'`
    CanonicalizedQueryString=$(urlencode $args "=&")
    StringToSign="GET&%2F&$(urlencode $CanonicalizedQueryString)"
    Signature=$(urlencode $(echo -n "$StringToSign" | openssl dgst -sha1 -hmac "$sk&" -binary | openssl base64))
    echo $(curl -k -s "https://alidns.aliyuncs.com/?$args&Signature=$Signature")
}

getValueFromJson() {
    local json="$1"
    local key="$2"
    echo $json | sed 's/":/:/g;s/"//g;s/,/\n/g' | grep $key | awk -F: '{ print $2 }'
}

DescribeSubDomainRecords() {
    send_request "Action=DescribeSubDomainRecords&SubDomain=$host.$domain&Type=$type"
}

UpdateDomainRecord() {
    local recordid=$(getValueFromJson `DescribeSubDomainRecords` "RecordId")
    send_request "Action=UpdateDomainRecord&RR=$host&RecordId=$recordid&Type=$type&Value=$downvalue"
}

AddDomainRecord() {
    send_request "Action=AddDomainRecord&DomainName=$domain&RR=$host&Type=$type&Value=$downvalue"
}

DeleteSubDomainRecords() {
    send_request "Action=DeleteSubDomainRecords&DomainName=$domain&RR=$host"
}

isCmdExist() {
    local ret=1
    if type $1 >/dev/null 2>&1;then
        ret=0
    fi
    return $ret
}

usage() {
    echo "Usage:"
    echo "-f file1  Read config from file1" 
    echo "-d test   DeleteSubDomainRecords of test.xx.com"
    echo "-h        Show usage"
    exit
}

set -- $(getopt -q hd:f: "$@")
while [ -n "$1" ]
do
    case "$1" in
        -h) usage;;
        -d) host=${2:1:!2-1};DeleteSubDomainRecords;exit;;
        -f) . ${2:1:!2-1};shift;;
        *);;
    esac
    shift
done

if [ "$type" = "AAAA" ];then
    iq=6
elif [ "$type" = "A" ];then
    iq=4
fi

if isCmdExist ipconfig;then
    get_downvalue() {
        local rst addr
        i=0
        while [ $i -lt ${#cmdlist[@]} ]
        do
            rst=$(eval ${cmdlist[i]})
            ipconfig | iconv -f gbk -t utf-8 | grep IPv$iq |grep ${rst} >/dev/null 2>&1
            if [ $? -eq 0 ];then
                addr=$rst
                break
            fi
            let i++
        done
        echo ${addr}
    }
elif isCmdExist ip;then
    get_downvalue() {
        local rst addr
        i=0
        while [ $i -lt ${#cmdlist[@]} ]
        do
            rst=$(eval ${cmdlist[i]})
            ip -$iq addr | grep ${rst} >/dev/null 2>&1
            if [ $? -eq 0 ];then
                addr=$rst
                break
            fi
            let i++
        done
        echo ${addr}
    }
fi

while [ $runnum -gt 0 ]
do
    runnum=$(expr $runnum - 1)
    datetime=$(date +%Y-%m-%d\ %T)
    echo 当前时间:$datetime

    rslt=`DescribeSubDomainRecords | grep TotalCount`
    if [ -z "$rslt" ];then
        echo "未获取到阿里云查询结果"
        sleep $rungap
        continue
    fi
    upvalue=$(getValueFromJson "$rslt" "Value")
    echo 域名指向:$upvalue

    downvalue=${downvalue:=`get_downvalue`}
    if [ -z "$downvalue" ]; then
        echo "未获取到本机地址"
        sleep $rungap
        continue
    fi
    echo 本机地址:$downvalue

    if [ "$upvalue" = "$downvalue" ]; then
        echo "已正确解析,无需更新。"
    elif [ -n "$upvalue" ]; then
        echo "更新解析记录..."
        UpdateDomainRecord
    else
        echo "添加解析记录..."
        AddDomainRecord
    fi
    break
done

接下来还需要在路由器防火墙放开端口。放行路由器下面终端的v6所有端口需要在路由器脚本“在防火墙规则启动后执行”处加入如下内容:

ip6tables -F
ip6tables -X
ip6tables -P INPUT ACCEPT
ip6tables -P OUTPUT ACCEPT
ip6tables -P FORWARD ACCEPT

路由器开放80、443等端口以实现外网访问则添加如下脚本:

ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A OUTPUT -p tcp --sport 80 -j ACCEPT
ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A OUTPUT -p tcp --sport 443 -j ACCEPT

PS.(图省事可以直接关闭防火墙×

需要注意的是,移动宽带的ipv6似乎屏蔽了80、443端口,想要外网访问只能使用其他端口。

校园网络

由于路由器(TR609 Padavan)使用校园无线网进行wisp无线桥接,无法直接为其下的终端分配ipv6,需要配置ipv6单独桥接。
首先控制台输入ifconfig,查看是哪个接口获取了v6地址。
将如下脚本加入路由器启动后执行脚本中即可。(两个eth3改为ifconfig获取的具体接口)

modprobe ip6table_mangle
ebtables -t broute -A BROUTING -p ! ipv6 -j DROP -i eth3
brctl addif br0 eth3

此模式实现将路由器的WAN口、LAN口以及WiFi桥接起来,所有的一级路由下发的v6地址通过桥直接分配给二级下面的终端,而v4地址走nat模式。简单来说就是就是路由对ipv4是路由器,对ipv6是一个交换机。

网络故障小插曲

用这个TR609+Padavan使用校园无线网进行wisp无线桥接的联网方案总是莫名其妙断流搞得很烦,因为以前用的是现在家里用的那个k2p,一直很稳,怀疑是TR609的无线信号不太行不适合做wisp桥接,于是又上pdd淘了一台k2p,没想到是22.10.3.42版本的官方固件得拆机才能刷breed,还好从箱子里翻出来一个usb转ttl的CH341G编程器能上手刷机,安照教程也是顺利完成了刷机工作。

此处内容需要评论回复后(审核通过)方可阅读。

具体刷机流程就不再赘述了,贴在参考里。简单概括一下备忘:

  1. 脚垫掰开拆机接线(注意TX RX反接的问题,而不是按照板子上的丝印接线)
  2. 编程器电压3V3打驱动看COM号
  3. 设置本机I 192.168.2.10,U 255.255.255.0,D 192.168.2.1
  4. breed.bin放Tftp64目录启动服务
  5. PuTTY串口57600速度连接
  6. 键盘连按9路由器插电开机
  7. 进入9号刷写模式按提示刷机即可
  8. Done!刷机成功

此处内容需要评论回复后(审核通过)方可阅读。

刚用上k2p的padavan似乎问题解决了,用几天之后发现经过路由器连接的网络(ipv4+ipv6)下行带宽异常的低(D:1 Mbps U:40 Mbps)。因为是直接导入TR609 padavan的配置文件的,怀疑有路由配置出了问题。一通设置更改之后问题神奇的解决了,可惜没有精确定位问题到底在哪:

  1. 无线5G高级设置启用MU-MIMO。
  2. 外网WAN关闭shortcut-fe加速,只启用硬件NAT加速,启用IPv6硬件加速。
  3. 内外LAN以太网交换机 接收端口之间的巨型帧改为up to 9000 bytes。

胡乱操作之后下行带宽总算比较正常了,但是ipv6桥接又莫名其妙抽风了,于是一步到位在ipv6设置里手动设了dns地址,重启了一下路由器,问题又神奇的解决了。接下来就希望这个路由器固件状态之后能正常养老了。

参考:
https://www.right.com.cn/forum/thread-4112503-1-1.html
https://www.right.com.cn/forum/thread-636761-1-1.html
https://www.right.com.cn/forum/thread-3790279-1-1.html
https://www.right.com.cn/forum/forum.php?mod=viewthread&tid=578699&page=1&extra=#pid3827816
https://www.jianshu.com/p/1eaecf2bc4cf
CH341G 驱动下载:http://www.wch.cn/download/CH341SER_EXE.html

文章目录