V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ca1123
V2EX  ›  宽带症候群

ER-X 分流问题,如何维护国内 IP 列表。

  •  
  •   ca1123 · 2021-06-21 18:23:13 +08:00 · 4490 次点击
    这是一个创建于 1285 天前的主题,其中的信息可能已经有所发展或是发生改变。
    上一贴: https://v2ex.com/t/784393
    前情提要:上一次讲到需要针对国内和国际线路创建路由表,由防火墙按照 IP 规则绑定到指定的路由表上去,以实现流量分发。

    那么用防火墙的话,carrionlee 老哥提出使用 network-group x Policy-Based-Routing(PBR),是很好的办法。比 chiphell 老哥逐条添加的办法好。这个办法底层是 Linux 的 ipset,很快。实际上 ER-X 用的 EdgeOS 就是换皮 VyOS,而 VyOS 的 PBR 底层就是用 ipset 实现的。自然 ER-X 的 PBR 也是用 ipset 的。

    这样的话,我需要 a,b,c,d 四步
    a) china ip list, 这个好办,github 上有。Archeb 提到用这个: https://github.com/17mon/china_ip_list

    b) PBR 这个也好办,carrionlee 告诉我用这个,主要意思就是目标 ip 在国内的话属于 chnroute,就用国内的路由表 main


    c) 接下来要用 bash 脚本把 a)中的 china ip list 导入,这是我迷惑的地方,看不太懂这个脚本,请大家帮我看看。问题想到哪儿说到哪儿多有重复。当一回伸手党不好意思了。
    我理解这个脚本是先检查 cache,有 cache 就从 cache 导入,否则从 ip 列表写入,同时保存到 cache 。

    第一:方括号里面的 -e 是检查是否存在的谓词么?
    第二:-! restore < 为啥要用叹号啊?是从缓存文件恢复的意思吧?
    第三:‘sed -e’ 是按行处理的意思么?是每一行就从管道线往下送一次么?
    第四:听说'awk'是匹配模式,可是这里是什么意思啊?$0 是什么?最后是补了一个 commit 么?如果没有匹配到模式,下一个管道线收到的是空么?
    第五:是全部一起传到 ipset -R 里,还是一行一行传的?
    第六:管道线是把上一个的结果作为参数,是一股脑弄下来的,还是一行一行弄下来的?
    第七:‘fi’是整个脚本结束,还是 if-then-else 结构结束啊?
    第八:就整个脚本老说。是不是每次更新了 ip 库都要把 cache 清除了?是不是这个脚本每次重启都要运行?

    d) ip 分流解决了,我就需要去弄 dns 了,暂时还没有什么想法。我能指定 ER-X 从特定的 WAN 口取 DNS 么?权益的可以先这么用一下。
    13 条回复    2021-06-22 21:01:25 +08:00
    sutra
        1
    sutra  
       2021-06-21 23:12:35 +08:00   ❤️ 1
    ```
    #!/bin/sh
    cache="/var/cache"

    rirs="${cache}/delegated-apnic-latest"
    expanded_rirs="${cache}/expanded-delegated-apnic-latest"
    asn_cache="${cache}/asn"

    geoip_database="http://geolite.maxmind.com/download/geoip/database"
    geoip_country_cache="${cache}/GeoIP/country"
    geoip_country_csv="${geoip_country_cache}/GeoLite2-Country-CSV"
    geoip_country_csv_zip="${geoip_country_csv}.zip"

    ip2location_lite_db1="https://download.ip2location.com/lite"
    ip2location_lite_db1_cache="${cache}/ip2location_lite_db1"
    ip2location_lite_db1_csv="${ip2location_lite_db1_cache}/IP2LOCATION-LITE-DB1.CSV"
    ip2location_lite_db1_csv_zip="${ip2location_lite_db1_csv}.ZIP"

    mkdir -p "${asn_cache}"
    mkdir -p "${geoip_country_csv}"
    mkdir -p "${ip2location_lite_db1_cache}"

    get.sh \
    -o "${rirs}" \
    -r 10 \
    "http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest" \
    && expand-rir-asn.sh \
    -i "${rirs}" \
    -o "${expanded_rirs}" \
    -C "${asn_cache}" \
    || exit 1

    get.sh \
    -o "${geoip_country_csv_zip}" \
    -r 10 \
    -m 200 \
    -n 204 \
    "${geoip_database}/GeoLite2-Country-CSV.zip"
    exit_status=$?
    if [ ${exit_status} -eq 200 ]; then
    unzip \
    -oqd "${geoip_country_cache}" \
    "${geoip_country_csv_zip}" \
    && rsync \
    "${geoip_country_cache}"/*/* \
    "${geoip_country_csv}/" \
    && rm \
    -r "${geoip_country_csv}"_*
    #elif [ ${exit_status} -ne 204 ]; then
    # exit $?
    fi

    get.sh \
    -o "${ip2location_lite_db1_csv_zip}" \
    -r 10 \
    -m 200 \
    -n 204 \
    "${ip2location_lite_db1}/IP2LOCATION-LITE-DB1.CSV.ZIP"
    exit_status=$?
    if [ ${exit_status} -eq 200 ]; then
    unzip \
    -oqd "${ip2location_lite_db1_cache}" \
    "${ip2location_lite_db1_csv_zip}"
    fi

    update-ipset.sh \
    -n "chnroute" \
    -i "${expanded_rirs}" \
    -g "${geoip_country_csv}" \
    -l "${ip2location_lite_db1_csv}" \
    -c "CN" \
    ```
    sutra
        2
    sutra  
       2021-06-21 23:35:36 +08:00   ❤️ 1
    > 第一:方括号里面的 -e 是检查是否存在的谓词么?
    https://en.wikibooks.org/wiki/Bash_Shell_Scripting

    > 第二:-! restore < 为啥要用叹号啊?是从缓存文件恢复的意思吧?
    重定向读入文件内容

    > 第三:‘sed -e’ 是按行处理的意思么?是每一行就从管道线往下送一次么?
    man sed

    > 第四:听说'awk'是匹配模式,可是这里是什么意思啊?$0 是什么?最后是补了一个 commit 么?如果没有匹配到模式,下一个管道线收到的是空么?
    https://github.com/wuzhouhui/awk

    > 第五:是全部一起传到 ipset -R 里,还是一行一行传的?
    全部

    第六:管道线是把上一个的结果作为参数,是一股脑弄下来的,还是一行一行弄下来的?
    > 全部

    第七:‘fi’是整个脚本结束,还是 if-then-else 结构结束啊?
    > if 倒过来写表示 if 结束了。

    第八:就整个脚本老说。是不是每次更新了 ip 库都要把 cache 清除了?是不是这个脚本每次重启都要运行?
    > 你重启看看 ipset list 有没有内容,ipset 有其它机制保证重启后还能恢复的。
    zdndk598
        3
    zdndk598  
       2021-06-22 07:21:03 +08:00 via iPhone
    建议重新学 shell script
    9yu
        4
    9yu  
       2021-06-22 08:20:34 +08:00 via Android
    建议重新学 shell script
    shyy228
        5
    shyy228  
       2021-06-22 08:28:41 +08:00
    建议重新学 shell script
    nbsn
        6
    nbsn  
       2021-06-22 12:24:40 +08:00
    @ca1123 楼主可以看下 ER-X 好像支持 bgp,我还是建议用动态路由。
    ca1123
        7
    ca1123  
    OP
       2021-06-22 13:48:52 +08:00
    @shyy228 你们三个队形这么整齐,我感觉自己都可以重开了。
    gqkkk
        8
    gqkkk  
       2021-06-22 15:19:19 +08:00
    -!, -exist
    Ignore errors when exactly the same set is to be created or already added entry is added or missing entry is deleted.

    restore
    Restore a saved session generated by save. The saved session can be fed from stdin or the option -file can be used to specify a filename instead of stdin.
    Please note, existing sets and elements are not erased by restore unless specified so in the restore file. All commands are allowed in restore mode except list, help, version, interactive mode and restore itself.
    gqkkk
        9
    gqkkk  
       2021-06-22 15:20:43 +08:00   ❤️ 1
    @sutra 人家问感叹号代表什么 不是标准输入
    gqkkk
        10
    gqkkk  
       2021-06-22 15:23:05 +08:00
    建议去看下 《 OReilly - Sed & Awk 2nd Edition 》
    zengming00
        11
    zengming00  
       2021-06-22 15:37:58 +08:00   ❤️ 1
    wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | awk -F\| '/CN\|ipv4/ { printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > /etc/chinaIP.txt
    sutra
        12
    sutra  
       2021-06-22 16:15:13 +08:00
    #1 的代码来着 https://github.com/sutra/update-ipset.sh ,贴得有点乱。
    ca1123
        13
    ca1123  
    OP
       2021-06-22 21:01:25 +08:00
    我找了个老哥帮我看了一下,下面是结果
    --------------------------------------------
    #!/bin/bash
    CHNROUTE_RULES=/config/user-data/chnroute.txt
    CHNROUTE_RULES_CHCHE=/config/user-data/chnroute.ipset

    if [-e $CHNROUTE_RULES_CHCHE]; then
    #中括号内 -e 判断文件是否存在

    ipset -! restore < $CHNROUTE_RULES_CHCHE
    # -! 参数忽略错误和提示信息,比如已经存在的 set 提示是否覆盖, 文件不存在报错
    # < 重定向符, 作为 ipset 的输入, 把文件内容输入到 ipset 命令中
    else
    sed -e "s/^/add chnroute &/g" $CHNROUTE_RULES | awk '{print $0} END {print "COMMIT"}' | ipset -R
    # | 管道符, 左边的输出 传到右边, 作为右边的输入
    # sed -e "s/^/add chnroute &/g" $CHNROUTE_RULES : 一行一行读取$CHNROUTE_RULES 文件,每行在开头插入"add chnroute &", -e 执行正则表达式脚本 "s/^/add chnroute &/g" s 替换 ^每行首段 /g 全行替换
    # awk $0 输出每行, END 在结束时候, 输出 COMMIT
    # 一行一行读取并执行,测试命令,实时输出,而不是最后整体输出: find .| awk '{print NR $0 " line end"} END {print "COMMIT"}'
    ipset save chnroute > $CHNROUTE_RULES_CHCHE
    #保存名为 chnroute 的集合,输出到文件当中
    fi
    #fi 结束,对应 if


    #参考:
    #一. -e 参数
    # if [[ -e readme.txt ]] ; then
    # echo '文件"readme.txt" 存在.'
    # else
    # echo '文件"readme.txt" 不存在.'
    # fi
    #二.ipset 参考链接 https://www.cnblogs.com/wn1m/p/10919940.html
    #三.sed 参考链接 http://c.biancheng.net/view/4028.html
    #四.awk 参考链接 https://www.runoob.com/linux/linux-comm-awk.html
    # 命令验证指令,NR 是打印输入的行号 sed -e "s/^/add chnroute &/g" 1.txt | awk '{print NR $0 " line end"} END {print "COMMIT"}' > 2.txt

    # 1.txt 内容为
    # 1
    # 2
    # 3

    # 输出的 2.txt
    # 1add chnroute 1 line end
    # 2add chnroute 2 line end
    # 3add chnroute 3 line end
    # COMMIT
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   966 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:23 · PVG 04:23 · LAX 12:23 · JFK 15:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.