<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>華鳥風月</title>
    <link>https://blog.9-ch.com/</link>
    <description>Recent content on 華鳥風月</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 09 Mar 2023 15:31:37 +0800</lastBuildDate><atom:link href="https://blog.9-ch.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>RouterOS 通过 OSPF IP分流非CN流量</title>
      <link>https://blog.9-ch.com/post/homelab-no-cn-routes/</link>
      <pubDate>Thu, 09 Mar 2023 15:31:37 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-no-cn-routes/</guid>
      <description>ROS ip 分流方案</description>
      <content:encoded><![CDATA[<p>主要适用于不想折腾PS/XBOX/Switch设备网关配置,又不希望出口网关为卵漏油/AIB的,或者怕折腾网络时家里断网影响家人的场景</p>
<h3 id="更新">更新</h3>
<ul>
<li>2022-06-18: 高版本ROS建立邻居困难问题建议尝试PTP/PTMP模式,并且对齐两侧参数(hello、dead count等),并检查224.0.0.0组播地址范围有无防火墙/路由规则影响导致的不可达问题</li>
<li>2023-01-28: 更新探针脚本, 调整文档结构</li>
</ul>
<h3 id="相关硬件">相关硬件</h3>
<ul>
<li>
<p>Mikrotik AC^2 (ros stable 7.2.3*)</p>
</li>
<li>
<p>NUC5i5MYBE (debian 11)</p>
<p>*<em>该版本OSPF似乎有bug,测试邻居离线时出现过一次不能自动删除路由,建议还是LT版本</em></p>
</li>
</ul>
<h3 id="网络结构">网络结构</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">AC^2--ETH1(192.168.0.254)--(192.168.0.1)光猫--Internet
</span></span><span class="line"><span class="cl">    |
</span></span><span class="line"><span class="cl">    |-ETH2-| birdge:lan
</span></span><span class="line"><span class="cl">    |-ETH3-| ip:192.168.1.1
</span></span><span class="line"><span class="cl">    |-ETH4-|----&gt; 192.168.1.0/24 SW
</span></span><span class="line"><span class="cl">    |
</span></span><span class="line"><span class="cl">    |-ETH5(192.168.255.1)--(192.168.255.254)NUC
</span></span></code></pre></td></tr></table>
</div>
</div><p>相关网段划分:</p>
<ul>
<li>192.168.0.0/24 &ndash;光猫/WAN口网段</li>
<li>192.168.1.0/24 &ndash;普通设备网段</li>
<li>192.168.255.0/24 &ndash;NUC网段</li>
</ul>
<h3 id="基础防火墙配置">基础防火墙配置</h3>
<p>不建议无脑抄,大部分配置有comment,建议按需添加</p>
<p>LAN包含lan桥ether5,WAN包括pppoe-out</p>
<details>
  <summary>ROS IPV4防火墙(较长已折叠)</summary>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall address-list
</span></span><span class="line"><span class="cl">add address=0.0.0.0/8 comment=&#34;defconf: RFC6890&#34; list=no_forward_ipv4
</span></span><span class="line"><span class="cl">add address=169.254.0.0/16 comment=&#34;defconf: RFC6890&#34; list=no_forward_ipv4
</span></span><span class="line"><span class="cl">add address=224.0.0.0/4 comment=&#34;defconf: multicast&#34; list=no_forward_ipv4
</span></span><span class="line"><span class="cl">add address=255.255.255.255 comment=&#34;defconf: RFC6890&#34; list=no_forward_ipv4
</span></span><span class="line"><span class="cl">add address=192.168.233.233 list=BOT
</span></span><span class="line"><span class="cl">add address=192.168.0.0/16 list=private
</span></span><span class="line"><span class="cl">add address=10.0.0.0/8 list=private
</span></span><span class="line"><span class="cl">add address=172.16.0.0/12 list=private
</span></span><span class="line"><span class="cl">/ip firewall filter
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=ANTI-BOT disabled=yes src-address-list=\
</span></span><span class="line"><span class="cl">    BOT
</span></span><span class="line"><span class="cl">add action=accept chain=input comment=Accept-OSPF protocol=ospf
</span></span><span class="line"><span class="cl">add action=accept chain=input comment=Accept-LAN-DNS dst-address=192.168.1.1 \
</span></span><span class="line"><span class="cl">    dst-port=53 protocol=udp
</span></span><span class="line"><span class="cl">add action=accept chain=input comment=Accept-NTP dst-port=123 protocol=udp
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=BLOCK-DNS dst-port=53 in-interface-list=\
</span></span><span class="line"><span class="cl">    WAN protocol=udp
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=BLOCK-DoT dst-port=53 in-interface-list=\
</span></span><span class="line"><span class="cl">    WAN protocol=tcp
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=BLOCK-HTTP dst-port=80 in-interface-list=\
</span></span><span class="line"><span class="cl">    WAN protocol=tcp
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=BLOCK-HTTPS dst-port=443 \
</span></span><span class="line"><span class="cl">    in-interface-list=WAN protocol=tcp
</span></span><span class="line"><span class="cl">add action=accept chain=input comment=\
</span></span><span class="line"><span class="cl">    &#34;defconf: accept established,related,untracked&#34; connection-state=\
</span></span><span class="line"><span class="cl">    established,related,untracked
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=&#34;defconf: drop invalid&#34; connection-state=\
</span></span><span class="line"><span class="cl">    invalid
</span></span><span class="line"><span class="cl">add action=accept chain=input comment=&#34;defconf: accept ICMP&#34; log-prefix=\
</span></span><span class="line"><span class="cl">    IPv4-ping protocol=icmp
</span></span><span class="line"><span class="cl">add action=accept chain=input comment=\
</span></span><span class="line"><span class="cl">    &#34;defconf: accept to local loopback (for CAPsMAN)&#34; dst-address=127.0.0.1
</span></span><span class="line"><span class="cl">add action=drop chain=input comment=&#34;defconf: drop all not coming from LAN&#34; \
</span></span><span class="line"><span class="cl">    in-interface-list=!LAN
</span></span><span class="line"><span class="cl">add action=accept chain=forward comment=&#34;defconf: accept in ipsec policy&#34; \
</span></span><span class="line"><span class="cl">    ipsec-policy=in,ipsec
</span></span><span class="line"><span class="cl">add action=accept chain=forward comment=&#34;defconf: accept out ipsec policy&#34; \
</span></span><span class="line"><span class="cl">    ipsec-policy=out,ipsec
</span></span><span class="line"><span class="cl">add action=fasttrack-connection chain=forward comment=&#34;defconf: fasttrack&#34; \
</span></span><span class="line"><span class="cl">    connection-state=established,related hw-offload=yes
</span></span><span class="line"><span class="cl">add action=accept chain=forward comment=\
</span></span><span class="line"><span class="cl">    &#34;defconf: accept established,related, untracked&#34; connection-state=\
</span></span><span class="line"><span class="cl">    established,related,untracked
</span></span><span class="line"><span class="cl">add action=drop chain=forward comment=&#34;defconf: drop invalid&#34; \
</span></span><span class="line"><span class="cl">    connection-state=invalid
</span></span><span class="line"><span class="cl">add action=drop chain=forward comment=\
</span></span><span class="line"><span class="cl">    &#34;defconf: drop all from WAN not DSTNATed&#34; connection-nat-state=!dstnat \
</span></span><span class="line"><span class="cl">    connection-state=new in-interface-list=WAN
</span></span><span class="line"><span class="cl">add action=drop chain=forward comment=&#34;defconf: drop bad forward IPs&#34; \
</span></span><span class="line"><span class="cl">    src-address-list=no_forward_ipv4
</span></span><span class="line"><span class="cl">add action=drop chain=forward comment=&#34;defconf: drop bad forward IPs&#34; \
</span></span><span class="line"><span class="cl">    dst-address-list=no_forward_ipv4
</span></span><span class="line"><span class="cl">/ip firewall nat
</span></span><span class="line"><span class="cl">add action=masquerade chain=srcnat comment=&#34;Hairpin NAT&#34; dst-address=\
</span></span><span class="line"><span class="cl">    192.168.1.0/24 out-interface=lan src-address=192.168.1.0/24
</span></span><span class="line"><span class="cl">add action=masquerade chain=srcnat comment=ONU dst-address=192.168.0.0/24 \
</span></span><span class="line"><span class="cl">    src-address=192.168.1.0/24
</span></span><span class="line"><span class="cl">add action=masquerade chain=srcnat comment=&#34;defconf: masquerade&#34; \
</span></span><span class="line"><span class="cl">    ipsec-policy=out,none out-interface-list=WAN
</span></span></code></pre></td></tr></table>
</div>
</div></details>
<h3 id="dns解析">DNS解析</h3>
<h4 id="ros配置">ROS配置</h4>
<p>使用netwatch检查NUC状态,离线时自动将dns切换为公共dns</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/system script
</span></span><span class="line"><span class="cl">add dont-require-permissions=yes name=use-default-dns owner=admin policy=\
</span></span><span class="line"><span class="cl">    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=&#34;/\
</span></span><span class="line"><span class="cl">    ip/dns/set allow-remote-requests=yes cache-size=4096KiB servers=119.29.29.\
</span></span><span class="line"><span class="cl">    29,223.5.5.5 \r\
</span></span><span class="line"><span class="cl">    \n/ip dns cache flush&#34;
</span></span><span class="line"><span class="cl">add dont-require-permissions=yes name=use-sgw-dns owner=admin policy=\
</span></span><span class="line"><span class="cl">    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=&#34;/\
</span></span><span class="line"><span class="cl">    ip/dns/set allow-remote-requests=yes cache-size=4096KiB servers=192.168.25\
</span></span><span class="line"><span class="cl">    5.254\r\
</span></span><span class="line"><span class="cl">    \n/ip dns cache flush&#34;
</span></span><span class="line"><span class="cl">/tool netwatch
</span></span><span class="line"><span class="cl">add down-script=use-default-dns host=192.168.255.254 interval=30s up-script=use-sgw-dns
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="可选1921681024网段dns劫持">(可选)192.168.1.0/24网段dns劫持</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall nat
</span></span><span class="line"><span class="cl">add action=dst-nat chain=dstnat comment=&#34;Hijacking for DNS&#34; dst-port=53 \
</span></span><span class="line"><span class="cl">    protocol=udp src-address=192.168.1.0/24 to-addresses=192.168.1.1 \
</span></span><span class="line"><span class="cl">    to-ports=53
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="debian配置">Debian配置</h4>
<p>SmartDNS分流解析</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">apt install smartdns
</span></span></code></pre></td></tr></table>
</div>
</div><p>配置/etc/smartdns/smartdns.conf 如下</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">bind</span> :53
</span></span><span class="line"><span class="cl">cache-size <span class="m">0</span>
</span></span><span class="line"><span class="cl">prefetch-domain no
</span></span><span class="line"><span class="cl">serve-expired no
</span></span><span class="line"><span class="cl">speed-check-mode ping,tcp:80
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">log-level info
</span></span><span class="line"><span class="cl">log-file /var/log/smartdns.log
</span></span><span class="line"><span class="cl">server 223.5.5.5:53
</span></span><span class="line"><span class="cl">server 119.29.29.29:53
</span></span><span class="line"><span class="cl">server-https https://dns.google/dns-query -check-edns -blacklist-ip -group GFW -exclude-default-group
</span></span><span class="line"><span class="cl">server-https https://1.1.1.1/dns-query -blacklist-ip -group GFW -exclude-default-group
</span></span><span class="line"><span class="cl">server-https https://cloudflare-dns.com/dns-query -blacklist-ip -group GFW -exclude-default-group
</span></span><span class="line"><span class="cl">conf-file /etc/smartdns/gfw.conf
</span></span></code></pre></td></tr></table>
</div>
</div><p>/etc/smartdns/gfw.conf 使用crontab更新</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="m">0</span> <span class="m">2</span> * * * curl -s https://raw.githubusercontents.com/RyoLee/gfwlist2smartdns/master/run.sh <span class="p">|</span> bash -s -- -o /etc/smartdns/gfw.conf <span class="o">&amp;&amp;</span> /etc/init.d/smartdns reload
</span></span></code></pre></td></tr></table>
</div>
</div><p>最终效果list内走223.5.5.5/119.29.29.29,list外走DoH</p>
<h3 id="ospf路由">OSPF路由</h3>
<h4 id="ros配置-1">ROS配置</h4>
<p>添加防火墙放行</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall mangle
</span></span><span class="line"><span class="cl">add action=mark-routing chain=prerouting new-routing-mark=main passthrough=\
</span></span><span class="line"><span class="cl">    yes protocol=ospf
</span></span><span class="line"><span class="cl">add action=mark-routing chain=prerouting dst-address-list=!private \
</span></span><span class="line"><span class="cl">    in-interface=ether5 new-routing-mark=bypass passthrough=yes
</span></span></code></pre></td></tr></table>
</div>
</div><p>Bypass路由表 &amp; OSPF</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/routing ospf instance
</span></span><span class="line"><span class="cl">add disabled=no name=sgw router-id=192.168.255.1 routing-table=main
</span></span><span class="line"><span class="cl">/routing ospf area
</span></span><span class="line"><span class="cl">add disabled=no instance=sgw name=sgw
</span></span><span class="line"><span class="cl">/routing table
</span></span><span class="line"><span class="cl">add disabled=no fib name=bypass
</span></span><span class="line"><span class="cl">/ip route
</span></span><span class="line"><span class="cl">add comment=&#34;BYPASS&#34; disabled=no distance=1 dst-address=0.0.0.0/0 \
</span></span><span class="line"><span class="cl">    gateway=pppoe-out pref-src=0.0.0.0 routing-table=bypass scope=30 \
</span></span><span class="line"><span class="cl">    suppress-hw-offload=no target-scope=10
</span></span><span class="line"><span class="cl">/routing ospf interface-template
</span></span><span class="line"><span class="cl">add area=sgw disabled=no interfaces=ether5
</span></span><span class="line"><span class="cl">/routing rule
</span></span><span class="line"><span class="cl">add action=lookup disabled=no routing-mark=bypass table=bypass
</span></span><span class="line"><span class="cl">add action=lookup disabled=no table=main
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="debian配置-1">Debian配置</h4>
<p>安装bird2</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">apt install bird2
</span></span></code></pre></td></tr></table>
</div>
</div><p>配置/etc/bird/bird.conf (网卡为enp0s25)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">log syslog all;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">router id 192.168.255.254;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">protocol device {
</span></span><span class="line"><span class="cl">	scan time 60;
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">protocol kernel {
</span></span><span class="line"><span class="cl">	ipv4 {
</span></span><span class="line"><span class="cl">	      import none;
</span></span><span class="line"><span class="cl">	      export all;
</span></span><span class="line"><span class="cl">	};
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">protocol static {
</span></span><span class="line"><span class="cl">	ipv4;
</span></span><span class="line"><span class="cl">	include &#34;routes4.conf&#34;;
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">protocol ospf v2 {
</span></span><span class="line"><span class="cl">    ecmp no;
</span></span><span class="line"><span class="cl">  	ipv4 {
</span></span><span class="line"><span class="cl">		export all;
</span></span><span class="line"><span class="cl">	};
</span></span><span class="line"><span class="cl">	area 0.0.0.0 {
</span></span><span class="line"><span class="cl">		interface &#34;enp0s25&#34; {
</span></span><span class="line"><span class="cl">			type broadcast;
</span></span><span class="line"><span class="cl">		};
</span></span><span class="line"><span class="cl">	};
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div><p>非CN流量出口为虚拟设备为utun,若使用TProxy则配置为对应的以太网网卡(如本例中enp0s25)</p>
<p><code>/etc/bird/routes4.conf</code> 使用crontab更新</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="m">0</span> <span class="m">2</span> * * * curl -s https://api.9-ch.com/ncr?device<span class="o">=</span>utun  -o /etc/bird/routes4.conf
</span></span><span class="line"><span class="cl"><span class="m">0</span> <span class="m">3</span> */1 * * /etc/init.d/bird reload
</span></span></code></pre></td></tr></table>
</div>
</div><p>心跳检查,若google 204服务检查失败则停止bird触发回落</p>
<p>探针脚本路径 <code>/opt/check/tun.sh</code> (已删除bark推送部分, 可自行按需添加)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nv">COUNT</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="nv">MAX_COUNT</span><span class="o">=</span><span class="m">6</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="o">[</span> <span class="nv">$COUNT</span> -lt <span class="nv">$MAX_COUNT</span> <span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nv">SER</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="nv">NET</span><span class="o">=</span><span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> <span class="k">$(</span>curl --connect-timeout <span class="m">10</span> --interface utun -w <span class="s2">&#34;%{http_code}&#34;</span> -s https://www.google.com/generate_204<span class="k">)</span> -eq <span class="m">204</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nv">NET</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> /etc/init.d/bird status<span class="p">|</span>grep Active<span class="p">|</span>grep -q running<span class="p">;</span><span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nv">SER</span><span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> <span class="nv">$NET</span> -eq <span class="m">1</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="o">[</span> <span class="nv">$SER</span> -eq <span class="m">0</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
</span></span><span class="line"><span class="cl">        /etc/init.d/bird start
</span></span><span class="line"><span class="cl">        <span class="c1"># curl -X &#34;POST&#34; &#34;https://******/push&#34; -H &#39;Content-Type: application/json; charset=utf-8&#39; -d $&#39;{&#34;body&#34;: &#34;***隧道已上线&#34;,&#34;device_key&#34;: &#34;******&#34;,&#34;level&#34;: &#34;passive&#34;,&#34;title&#34;: &#34;网络探针&#34;}&#39;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">exit</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[</span> <span class="nv">$NET</span> -eq <span class="m">0</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="o">[</span> <span class="nv">$SER</span> -eq <span class="m">1</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
</span></span><span class="line"><span class="cl">        <span class="nb">let</span> <span class="nv">COUNT</span><span class="o">+=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="o">[</span> <span class="nv">$COUNT</span> -eq <span class="nv">$MAX_COUNT</span> <span class="o">]</span><span class="p">;</span><span class="k">then</span>
</span></span><span class="line"><span class="cl">            /etc/init.d/bird stop
</span></span><span class="line"><span class="cl">            <span class="c1"># curl -X &#34;POST&#34; &#34;https://******/push&#34; -H &#39;Content-Type: application/json; charset=utf-8&#39; -d $&#39;{&#34;body&#34;: &#34;***隧道已离线&#34;,&#34;device_key&#34;: &#34;******&#34;,&#34;level&#34;: &#34;passive&#34;,&#34;title&#34;: &#34;网络探针&#34;}&#39;</span>
</span></span><span class="line"><span class="cl">            <span class="nb">exit</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">        <span class="k">fi</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="nb">exit</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">* * * * * bash /opt/check/tun.sh
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="ros-ddns失效问题">ROS DDNS失效问题</h3>
<p>见前文<a href="https://blog.9-ch.com/post/homelab-ros-ospf/#ros-ddns%e5%a4%b1%e6%95%88">ros-ddns失效</a></p>
<h3 id="参考信息">参考信息</h3>
<h4 id="同网段分流openwrt方案">同网段分流openwrt方案</h4>
<p>见前文<a href="https://blog.9-ch.com/post/homelab-ros-ospf/">RouterOS 通过 OSPF IP分流至 OpenWrt</a></p>
<p>零散问题比较多, 本方案为基于以上测试经验改进出新方案,非CN IP流量出口改为使用运行debian的一台NUC</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>本站域名已迁移至9-ch.com</title>
      <link>https://blog.9-ch.com/post/base-domain-update/</link>
      <pubDate>Thu, 09 Mar 2023 15:31:19 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/base-domain-update/</guid>
      <description>站点维护日志</description>
      <content:encoded><![CDATA[<h3 id="站点维护日志">站点维护日志</h3>
<p>考虑到 IDN 域名对非中文用户不友好、部分搜索引擎收录异常等诸多问题，本站已经迁移至新域名 <a href="https://9-ch.com">9-ch.com</a></p>
<p>原域名 <a href="https://xn--7ovq92diups1e.com">花鸟风月.com</a> 将继续提供 api 服务至 <strong>2023-04-07</strong> ，请尽快迁移使用 <code>api.xn--7ovq92diups1e.com</code> 的服务至新域名 <code>api.9-ch.com</code></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>通过Python自动生成Beancount月度账单</title>
      <link>https://blog.9-ch.com/post/homelab-beancount-bill/</link>
      <pubDate>Fri, 03 Feb 2023 14:37:13 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-beancount-bill/</guid>
      <description>通过BQL查询生成Latex格式Beancount月度账单, 再导出为PDF后发送到邮箱</description>
      <content:encoded><![CDATA[<p>
  <img loading="lazy" src="https://s1.ax1x.com/2023/02/03/pSsQws1.png" alt="截图"  /></p>
<h3 id="背景">背景</h3>
<p>最近几个月开始使用 Beancount 记账, 并且每月通过 Github actions 自动生成一份 markdown 格式的汇总单(<a href="https://www.bmpi.dev/self/beancount-my-accounting-tool-v2/#%E5%AE%9A%E6%97%B6%E8%8E%B7%E5%8F%96%E6%94%B6%E6%94%AF%E6%8A%A5%E8%A1%A8">参考</a>), 由于觉得显示效果不太好, 决定手撸一份新的生成程序</p>
<h3 id="代码">代码</h3>
<h4 id="文档生成">文档生成</h4>
<p>首先是生成 latex 文档的部分, 直接使用文本模板+占位符替换的模式实现, 这样就不用和 latex 的包打交道了(懒狗</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env python3</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -*- coding: UTF-8 -*-</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">datetime</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">decimal</span> <span class="kn">import</span> <span class="n">Decimal</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">beancount</span> <span class="kn">import</span> <span class="n">loader</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">beancount.query</span> <span class="kn">import</span> <span class="n">query</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">calendar</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">dateutil.relativedelta</span> <span class="kn">import</span> <span class="n">relativedelta</span>
</span></span><span class="line"><span class="cl"><span class="n">_template</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;&#39;&#39;
</span></span></span><span class="line"><span class="cl"><span class="s1">\documentclass[UTF8]</span><span class="si">{ctexart}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\usepackage</span><span class="si">{multicol}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\usepackage</span><span class="si">{geometry}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\setlength\columnsep</span><span class="si">{1cm}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\geometry{a4paper,left=1.5cm,right=1.5cm,top=0cm,bottom=1.5cm}
</span></span></span><span class="line"><span class="cl"><span class="s1">\columnseprule=1pt
</span></span></span><span class="line"><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\title{Monthly Beancount Report}
</span></span></span><span class="line"><span class="cl"><span class="s1">\author{GitHub Actions}
</span></span></span><span class="line"><span class="cl"><span class="s1">\date</span><span class="si">{}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{document}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\maketitle
</span></span></span><span class="line"><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">\small
</span></span></span><span class="line"><span class="cl"><span class="s1">\textbf{\Large Statement of Comprehensive Income} \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\date{ENV_YEAR-ENV_MONTH-01 to ENV_YEAR-ENV_MONTH-ENV_DAY}
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{multicols}{2}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\textbf{Income Detail} \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">ACCOUNT &amp; TOTAL(CNY) \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">ENV_LINES_INCOME
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\vfill\null
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">Total &amp; ENV_TOTAL_INCOME \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\columnbreak
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\textbf{Expenses Detail} \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">ACCOUNT &amp; TOTAL(CNY) \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">ENV_LINES_EXPENSES
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\vfill\null
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">Total &amp; ENV_TOTAL_EXPENSES \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{multicols}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">Net Profit &amp; ENV_NET_PROFIT \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\vfill\null
</span></span></span><span class="line"><span class="cl"><span class="s1">\textbf{\Large Statement of Financial Position} \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\date{As of ENV_YEAR-ENV_MONTH-ENV_DAY}
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{multicols}{2}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\textbf{Assets Detail} \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">ACCOUNT &amp; TOTAL(CNY) \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">ENV_LINES_ASSETS
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\vfill\null
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">Total &amp; ENV_TOTAL_ASSETS \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\columnbreak
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\textbf{Liabilities Detail} \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">ACCOUNT &amp; TOTAL(CNY) \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">ENV_LINES_LIABILITIES
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\vfill\null
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">Total &amp; ENV_TOTAL_LIABILITIES \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{multicols}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\begin{tabular*}{\hsize}{@</span><span class="si">{}</span><span class="s1">@{\extracolsep{\fill}}lr@</span><span class="si">{}</span><span class="s1">}
</span></span></span><span class="line"><span class="cl"><span class="s1">\hline
</span></span></span><span class="line"><span class="cl"><span class="s1">Debt Ratio &amp; ENV_DEBT_RATIO \\
</span></span></span><span class="line"><span class="cl"><span class="s1">\end{tabular*}
</span></span></span><span class="line"><span class="cl"><span class="s1">\vfill\null
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{center}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">\end</span><span class="si">{document}</span><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">&#39;&#39;&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Buffer</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">replace</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">_old</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">_new</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">_old</span><span class="p">,</span> <span class="n">_new</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># load file</span>
</span></span><span class="line"><span class="cl">    <span class="n">ledger_data</span><span class="p">,</span> <span class="n">errors</span><span class="p">,</span> <span class="n">options</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load_file</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">(),</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># init buffer</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span> <span class="o">=</span> <span class="n">Buffer</span><span class="p">(</span><span class="n">_template</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># init time</span>
</span></span><span class="line"><span class="cl">    <span class="n">lm</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">relativedelta</span><span class="p">(</span><span class="n">months</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">year</span> <span class="o">=</span> <span class="n">lm</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&#34;%Y&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">month</span> <span class="o">=</span> <span class="n">lm</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&#34;%m&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_YEAR</span> <span class="o">=</span> <span class="n">year</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_MONTH</span> <span class="o">=</span> <span class="n">month</span>
</span></span><span class="line"><span class="cl">    <span class="n">year</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">year</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">month</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">month</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">day</span> <span class="o">=</span> <span class="n">calendar</span><span class="o">.</span><span class="n">monthrange</span><span class="p">(</span><span class="n">year</span><span class="p">,</span> <span class="n">month</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_DAY</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">day</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_LINES_INCOME</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT account, abs(sum(cost(position))) as total WHERE account ~ &#34;^Income:*&#34; and year = &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month = &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="sa">r</span><span class="s1">&#39; GROUP BY month, account ORDER BY account, total DESC&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_LINES_INCOME</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">rrow</span> <span class="ow">in</span> <span class="n">rrows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">ENV_LINES_INCOME</span> <span class="o">+=</span> <span class="n">rrow</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; &amp; &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrow</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; </span><span class="se">\\</span><span class="s1">&#39;</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_TOTAL_INCOME</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT abs(sum(cost(position))) WHERE account ~ &#34;^Income:*&#34; and year = &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month =  &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; GROUP BY month&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_TOTAL_INCOME</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_LINES_EXPENSES</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT account, sum(cost(position)) as total WHERE account ~ &#34;^Expenses:*&#34; and year = &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month = &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="sa">r</span><span class="s1">&#39; GROUP BY month, account ORDER BY account, total DESC&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_LINES_EXPENSES</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">rrow</span> <span class="ow">in</span> <span class="n">rrows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">ENV_LINES_EXPENSES</span> <span class="o">+=</span> <span class="n">rrow</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; &amp; &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrow</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; </span><span class="se">\\</span><span class="s1">&#39;</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_TOTAL_EXPENSES</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT sum(cost(position)) WHERE account ~ &#34;^Expenses:*&#34; and year = &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month = &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; GROUP BY month&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_TOTAL_EXPENSES</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_NET_PROFIT</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT abs(sum(cost(position))) WHERE year = &#39;</span> <span class="o">+</span> <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month = &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_MONTH</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="sa">r</span><span class="s1">&#39; and ( account ~ &#34;^Expenses:*&#34; or account ~ &#34;^Income:*&#34; ) GROUP BY month&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_NET_PROFIT</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_LINES_ASSETS</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT account, sum(cost(position)) as total WHERE account ~ &#34;^Assets:*&#34; and year &lt;= &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month &lt;= &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and day &lt;= &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_DAY</span><span class="o">+</span><span class="sa">r</span><span class="s1">&#39; ORDER BY account, total DESC&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_LINES_ASSETS</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">rrow</span> <span class="ow">in</span> <span class="n">rrows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">ENV_LINES_ASSETS</span> <span class="o">+=</span> <span class="n">rrow</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; &amp; &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrow</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; </span><span class="se">\\</span><span class="s1">&#39;</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_TOTAL_ASSETS</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT sum(cost(position)) as total WHERE account ~ &#34;^Assets:*&#34; and year &lt;= &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month &lt;= &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and day &lt;= &#39;</span><span class="o">+</span><span class="n">ENV_DAY</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_TOTAL_ASSETS</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_LINES_LIABILITIES</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT account, abs(sum(cost(position))) as total WHERE account ~ &#34;^Liabilities:*&#34; and year &lt;= &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month &lt;= &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and day &lt;= &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_DAY</span><span class="o">+</span><span class="sa">r</span><span class="s1">&#39; ORDER BY account, total DESC&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_LINES_LIABILITIES</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">rrow</span> <span class="ow">in</span> <span class="n">rrows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">ENV_LINES_LIABILITIES</span> <span class="o">+=</span> <span class="n">rrow</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; &amp; &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">            <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrow</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; </span><span class="se">\\</span><span class="s1">&#39;</span> <span class="o">+</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_TOTAL_LIABILITIES</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql_query</span> <span class="o">=</span> <span class="sa">r</span><span class="s1">&#39;SELECT abs(sum(cost(position))) as total WHERE account ~ &#34;^Liabilities:*&#34; and year &lt;= &#39;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">        <span class="n">ENV_YEAR</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and month &lt;= &#39;</span> <span class="o">+</span> <span class="n">ENV_MONTH</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39; and day &lt;= &#39;</span><span class="o">+</span><span class="n">ENV_DAY</span>
</span></span><span class="line"><span class="cl">    <span class="n">rrows</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">run_query</span><span class="p">(</span><span class="n">ledger_data</span><span class="p">,</span> <span class="n">options</span><span class="p">,</span> <span class="n">sql_query</span><span class="p">,</span> <span class="n">numberify</span><span class="o">=</span><span class="kc">True</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_TOTAL_LIABILITIES</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{0:.2f}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rrows</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># ENV_DEBT_RATIO</span>
</span></span><span class="line"><span class="cl">    <span class="n">ENV_DEBT_RATIO</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">{:.2%}</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">Decimal</span><span class="p">(</span><span class="n">ENV_TOTAL_LIABILITIES</span><span class="p">)</span><span class="o">/</span><span class="n">Decimal</span><span class="p">(</span><span class="n">ENV_TOTAL_ASSETS</span><span class="p">))</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;%&#39;</span><span class="p">,</span> <span class="sa">r</span><span class="s1">&#39;\%&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_YEAR&#34;</span><span class="p">,</span> <span class="n">ENV_YEAR</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_MONTH&#34;</span><span class="p">,</span> <span class="n">ENV_MONTH</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_DAY&#34;</span><span class="p">,</span> <span class="n">ENV_DAY</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_LINES_INCOME&#34;</span><span class="p">,</span> <span class="n">ENV_LINES_INCOME</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_TOTAL_INCOME&#34;</span><span class="p">,</span> <span class="n">ENV_TOTAL_INCOME</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_LINES_EXPENSES&#34;</span><span class="p">,</span> <span class="n">ENV_LINES_EXPENSES</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_TOTAL_EXPENSES&#34;</span><span class="p">,</span> <span class="n">ENV_TOTAL_EXPENSES</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_NET_PROFIT&#34;</span><span class="p">,</span> <span class="n">ENV_NET_PROFIT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_LINES_ASSETS&#34;</span><span class="p">,</span> <span class="n">ENV_LINES_ASSETS</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_TOTAL_ASSETS&#34;</span><span class="p">,</span> <span class="n">ENV_TOTAL_ASSETS</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_LINES_LIABILITIES&#34;</span><span class="p">,</span> <span class="n">ENV_LINES_LIABILITIES</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_TOTAL_LIABILITIES&#34;</span><span class="p">,</span> <span class="n">ENV_TOTAL_LIABILITIES</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">_buffer</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;ENV_DEBT_RATIO&#34;</span><span class="p">,</span> <span class="n">ENV_DEBT_RATIO</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">_buffer</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>可以在这个<a href="https://github.com/RyoLee/beancount-template/blob/master/tool/get_bill.py">github 仓库</a>查看后续更新</p>
<h4 id="github-actions-配置">Github actions 配置</h4>
<p>Github actions 配置部分比较简单, 每月月初定时生成后邮件发出即可</p>
<p>敏感信息已用*号代替, 请自行替换(邮箱密码需在 github 添加 secrets <code>MAIL_PASSWORD</code>)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">schedule-email</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schedule</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cron</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;30 16 1 */1 *&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">workflow_dispatch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">make-monthly-bill</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">make-monthly-bill</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Checkout repository</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@master</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Set up Python3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/setup-python@v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">python-version</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;3.7&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">BSFishy/pip-action@v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">packages</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">            beancount</span><span class="w">            
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">python3 tool/get_bill.py main.bean &gt; report.tex</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Github Action for LaTeX</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">xu-cheng/latex-action@v2</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">root_file</span><span class="p">:</span><span class="w"> </span><span class="l">report.tex</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">latexmk_use_xelatex</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">send-email</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">dawidd6/action-send-mail@v3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">with</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">server_address</span><span class="p">:</span><span class="w"> </span><span class="cp">******</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">server_port</span><span class="p">:</span><span class="w"> </span><span class="cp">******</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="cp">******</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">password</span><span class="p">:</span><span class="w"> </span><span class="l">${{secrets.MAIL_PASSWORD}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">subject</span><span class="p">:</span><span class="w"> </span><span class="l">Monthly Beancount Report</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">attachments</span><span class="p">:</span><span class="w"> </span><span class="l">./report.pdf</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">to</span><span class="p">:</span><span class="w"> </span><span class="cp">******</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">from</span><span class="p">:</span><span class="w"> </span><span class="cp">******</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>通过DNS与Nginx锁定并加速Steam下载(CDN)</title>
      <link>https://blog.9-ch.com/post/homelab-steam-cdn/</link>
      <pubDate>Sat, 28 Jan 2023 17:08:11 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-steam-cdn/</guid>
      <description>通过DNS与Nginx锁定并加速Steam下载(CDN)</description>
      <content:encoded><![CDATA[<h3 id="更新记录">更新记录</h3>
<ul>
<li>2024-09-24: 简化配置, 通过lancache机制直接实现对CDN的控制</li>
</ul>
<h3 id="为什么要手动锁定">为什么要手动锁定</h3>
<p>当使用透明网关对内网进行加速时(包括部分游戏加速器的特定工作模式), 会因为Steam根据当前ip判断自动切换到ip对应地区的下载CDN, 造成隧道流量的浪费甚至产生反效果导致下载缓慢</p>
<h3 id="如何判断是否需要使用该方案">如何判断是否需要使用该方案</h3>
<p>最简单的办法就是不做任何其他配置的情况下(若使用加速器需要先打开加速器), 打开 <code>Steam--设置--下载</code> 检查下载地区, 若显示为任意大陆地区城市则大概率不需要本方案修改(这个选项城市其实是假的, 只要是任意大陆城市本质都一样)</p>
<p>若显示为透明网关对应隧道/加速器ip地区, 则可以考虑使用本方案</p>
<p>另外也可以通过 <code>Win+R</code> 执行 <code>steam://open/console</code> 调出Steam控制台来查看信息判断</p>
<ol>
<li>执行 <code>user_info</code> 查看IPCountry是否为CN</li>
<li>执行 <code>download_sources</code> 直接查看当前下载服务器是否为国内CDN</li>
</ol>
<p>常见国内服务器域名可以在 <a href="https://github.com/v2fly/domain-list-community/blob/master/data/steam">CDN清单</a> 查到</p>
<h3 id="相关配置">相关配置</h3>
<p>本方案由两部分组成</p>
<ul>
<li>DNS</li>
<li>Nginx</li>
</ul>
<h4 id="dns">DNS</h4>
<p>下面以ROS为例, 假设Nginx服务所在IP为内网192.168.1.100, 需要劫持的域名见如下配置</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip dns static
</span></span><span class="line"><span class="cl">add address=192.168.1.100 name=lancache.steamcontent.com
</span></span></code></pre></td></tr></table>
</div>
</div><p>配置完毕后将PC的DNS指向ROS后即可, 另外也可以通过dstnat将dst port 53的udp流量直接劫持给ROS</p>
<p>以ROS ip 192.168.1.1, PC网段192.168.1.0/24为例, 解析劫持配置如下</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall nat
</span></span><span class="line"><span class="cl">add action=dst-nat chain=dstnat comment=&#34;Hijacking for DNS&#34; dst-port=53 protocol=udp src-address=192.168.1.0/24 to-addresses=192.168.1.1 to-ports=53
</span></span></code></pre></td></tr></table>
</div>
</div><p>也可以直接在Steam运行机器通过Hosts文件配置</p>
<h4 id="nginx转发配置">Nginx转发配置</h4>
<p>可选的CDN很多, 这里以阿里云 <code>xz.pphimalayanrt.com</code> 为例, 若使用其他CDN修改配置中对应 <code>server</code> 与 <code>Host</code> 即可</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">upstream steam-upstream {
</span></span><span class="line"><span class="cl">    server xz.pphimalayanrt.com;
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">server {
</span></span><span class="line"><span class="cl">    listen 80;
</span></span><span class="line"><span class="cl">    server_name lancache.steamcontent.com *.steamcontent.com;
</span></span><span class="line"><span class="cl">    slice 8m;
</span></span><span class="line"><span class="cl">    proxy_set_header Range $slice_range;
</span></span><span class="line"><span class="cl">    location / {
</span></span><span class="line"><span class="cl">        proxy_pass http://steam-upstream;
</span></span><span class="line"><span class="cl">        proxy_set_header Host &#34;xz.pphimalayanrt.com&#34;;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div><p>若阿里云速度不理想可以参考 <a href="https://www.dogfight360.com/blog/knowledge-base/%E5%A6%82%E4%BD%95%E6%8F%90%E9%AB%98steam%E7%9A%84%E4%B8%8B%E8%BD%BD%E9%80%9F%E5%BA%A6%E4%B8%AD%E5%9B%BD%E5%A4%A7%E9%99%86%E5%9C%B0%E5%8C%BA/">dogfight360 的这篇 blog</a> 自行逐个测试, 根据自身网络选出最佳CDN</p>
<h3 id="检查是否生效">检查是否生效</h3>
<p>随便下载个游戏, 检查Nginx日志, 会发现有大量的 <code>Valve/Steam HTTP Client 1.0</code> 访问记录, 即说明当前运行正常</p>
<h3 id="其他方案">其他方案</h3>
<p>Dogfight360的 <a href="https://www.dogfight360.com/blog/1531/">Steam下载CDN重定向</a> 非常好用的锁定工具 <del>除了每次要手动启动</del></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Emby 弹幕插件</title>
      <link>https://blog.9-ch.com/post/homelab-emby-danmaku/</link>
      <pubDate>Mon, 08 Aug 2022 18:44:25 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-emby-danmaku/</guid>
      <description>Emby danmaku extension</description>
      <content:encoded><![CDATA[<p>
  <img loading="lazy" src="https://s1.ax1x.com/2022/08/09/vltmKs.png" alt="截图"  /></p>
<h3 id="项目主页">项目主页</h3>
<p><a href="https://github.com/RyoLee/emby-danmaku">RyoLee/emby-danmaku</a></p>
<h3 id="安装">安装</h3>
<p>任意一种方式安装即可</p>
<h4 id="浏览器方式推荐">浏览器方式(推荐)</h4>
<ol>
<li><a href="https://www.tampermonkey.net/">Tampermonkey</a></li>
<li><a href="https://cdn.jsdelivr.net/gh/RyoLee/emby-danmaku@gh-pages/ede.user.js">添加脚本</a></li>
</ol>
<h4 id="服务端方式">服务端方式</h4>
<p>路径 /system/dashboard-ui/index.html
在<code>&lt;/body&gt;</code>前添加如下标签</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&lt;script src=&#34;https://cdn.jsdelivr.net/gh/RyoLee/emby-danmaku@gh-pages/ede.user.js&#34; defer&gt;&lt;/script&gt;
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="客户端方式">客户端方式</h4>
<p>类似服务端方式,解包后修改dashboard-ui/index.html再重新打包即可,iOS需要通过类似AltStore方式自签,请自行Google解决</p>
<h3 id="界面">界面</h3>
<p>插件运行后会在界面左下侧追加4个新按钮,分别为:</p>
<ul>
<li>弹幕开关</li>
<li>手动匹配</li>
<li>简繁转换</li>
<li>弹幕信息(触发右下角消息)</li>
</ul>
<h3 id="补充说明">补充说明</h3>
<p>弹幕来源为<a href="https://www.dandanplay.com/">弹弹play</a> 已开启弹幕聚合(A/B/C 站等弹幕融合)</p>
<p>因播放文件在emby中与上游弹弹play的名称可能存在不同(如&quot;彻夜之歌&quot;&lt;&ndash;&gt;&ldquo;夜曲&rdquo;),或因为存在多季/剧场版/OVA导致搜索匹配错误,首次播放时请检查当前弹幕信息是否正确匹配,若匹配错误可尝试手动匹配</p>
<p>匹配完成后对应关系会保存在浏览器本地存储中,后续播放(包括同季的其他集)会优先按照保存的匹配记录载入弹幕</p>
<h3 id="todo">TODO</h3>
<ul>
<li><input disabled="" type="checkbox"> 屏蔽规则导入</li>
<li><input checked="" disabled="" type="checkbox"> 简繁转换开关</li>
<li><input disabled="" type="checkbox"> 弹幕加载失败自动重试</li>
</ul>
<h3 id="参考项目">参考项目</h3>
<p><a href="https://github.com/susundingkai/emby-danmaku">susundingkai/emby-danmaku</a></p>
<p>主要差异:</p>
<ul>
<li>配置存储改为 localstorage</li>
<li>弹幕数据跨域问题通过 cloudflare 的 workers 处理绕过</li>
<li>通过播放对象的 item id 从 emby 的 api 获取数据,不再使用页面对象提取,更新导致出错概率大幅下降(顺便修好了播放下一集不能加载的问题)</li>
</ul>
<h3 id="license">License</h3>
<p><a href="https://github.com/RyoLee/emby-danmaku/blob/master/LICENSE">MIT License</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>RouterOS 端口扫描防御</title>
      <link>https://blog.9-ch.com/post/homelab-ros-anti-scan/</link>
      <pubDate>Mon, 06 Jun 2022 20:29:11 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-ros-anti-scan/</guid>
      <description>RouterOS 入侵检测</description>
      <content:encoded><![CDATA[<p>通过ROS防火墙检测并屏蔽端口扫描行为,并使用bark将屏蔽事件发送至手机</p>
<h3 id="ros配置">ROS配置</h3>
<h4 id="屏蔽列表ip">屏蔽列表IP</h4>
<p>屏蔽BOT列表中的数据包,建议将这一条的优先级提高到最高(即编号#1)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall raw
</span></span><span class="line"><span class="cl">add action=drop chain=prerouting comment=ANTI-BOT src-address-list=BOT
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="指定端口方式">指定端口方式</h4>
<p>对于常见家用环境下不使用的高危TCP端口进行记录,在连续尝试3次(1分钟超时)后拉黑IP 7天</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall raw
</span></span><span class="line"><span class="cl">add action=add-src-to-address-list address-list=BOT address-list-timeout=1w chain=prerouting comment=ANTI-SCAN dst-port=20-23,53,80,135,139,443,445,1433,2049,3389,5900,8080,8089 log=yes log-prefix=ANTI-SCAN protocol=tcp src-address-list=SCAN_S2
</span></span><span class="line"><span class="cl">add action=add-src-to-address-list address-list=SCAN_S2 address-list-timeout=1m chain=prerouting comment=ANTI-SCAN dst-port=20-23,53,80,135,139,443,445,1433,2049,3389,5900,8080,8089 protocol=tcp src-address-list=SCAN_S1
</span></span><span class="line"><span class="cl">add action=add-src-to-address-list address-list=SCAN_S1 address-list-timeout=1m chain=prerouting comment=ANTI-SCAN dst-port=20-23,53,80,135,139,443,445,1433,2049,3389,5900,8080,8089 in-interface-list=WAN protocol=tcp
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="psd方式">PSD方式</h4>
<p>如果觉得搞一堆端口配置太麻烦,也可以用内置的PSD来实现,默认规则为: 3秒内低位端口计3分,高位端口计1分,合计21分触发</p>
<p>实测默认规则针对端口批量扫描检出率较高,针对定向端口弱口令爆破识别效果稍差,建议自行调整参数,或者结合指定端口方式配置</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/ip firewall raw
</span></span><span class="line"><span class="cl">add action=add-src-to-address-list address-list=BOT address-list-timeout=1w chain=prerouting comment=ANTI-SCAN in-interface-list=WAN log=yes log-prefix=ANTI-SCAN protocol=tcp psd=21,3s,3,1
</span></span><span class="line"><span class="cl">add action=add-src-to-address-list address-list=BOT address-list-timeout=1w chain=prerouting comment=ANTI-SCAN in-interface-list=WAN log=yes log-prefix=ANTI-SCAN protocol=udp psd=21,3s,3,1
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="rsyslog配置">Rsyslog配置</h4>
<p>如果不需要推送屏蔽完成上述配置即可</p>
<p>假设接收日志机器ip为192.168.1.100</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/system logging action
</span></span><span class="line"><span class="cl">set remote=192.168.1.100 remote
</span></span><span class="line"><span class="cl">/system logging
</span></span><span class="line"><span class="cl">add action=remote topics=info
</span></span></code></pre></td></tr></table>
</div>
</div><p>如果不需要其他消息可以在topics中加上firewall,仅过滤并转发防火墙的log</p>
<h3 id="linux配置">Linux配置</h3>
<p>假设接收设备ip为192.168.1.100,ROS ip为192.168.1.1</p>
<p>修改/etc/rsyslog.conf如下部分,去除最前面的&quot;#&ldquo;解除注释,启用udp模式rsyslog接收ros发送过来的日志</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">module(load=&#34;imudp&#34;)
</span></span><span class="line"><span class="cl">input(type=&#34;imudp&#34; port=&#34;514&#34;)                              # 可按需修改端口,需要同步修改ros配置端口
</span></span></code></pre></td></tr></table>
</div>
</div><p>再添加如下规则</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">:msg, contains, &#34;ANTI-SCAN&#34;     ^/opt/bark/router.sh        # 调用脚本处理并发送bark消息
</span></span><span class="line"><span class="cl">:FROMHOST-IP, isequal,&#34;192.168.1.1&#34; /var/log/router.log     # 汇总ros日志
</span></span><span class="line"><span class="cl">:FROMHOST-IP, isequal,&#34;192.168.1.1&#34; ~                       # 防止重复收集到message中
</span></span></code></pre></td></tr></table>
</div>
</div><p>修改/etc/logrotate.d/rsyslog 在花括号前添加一行,配置日志老化</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/var/log/router.log
</span></span></code></pre></td></tr></table>
</div>
</div><p>创建脚本 /opt/bark/router.sh 并添加权限(chmod +x /opt/bark/router.sh),消息格式可自行按需调整</p>
<p>YOUR_BARK_SERVER 替换为BARK服务器ip/域名</p>
<p>YOUR_DEVICE_ID 替换为接收设备ID</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="nv">msg</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$*</span><span class="s2">&#34;</span> <span class="p">|</span>tr <span class="s2">&#34; &#34;</span> <span class="s2">&#34;\n&#34;</span><span class="p">|</span>grep <span class="s1">&#39;\-&gt;&#39;</span><span class="p">|</span>grep -E <span class="s2">&#34;(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)&#34;</span><span class="p">|</span>tr -d <span class="s2">&#34;,&#34;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">curl -X <span class="s2">&#34;POST&#34;</span> <span class="s2">&#34;https://YOUR_BARK_SERVER/push&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>     -H <span class="s1">&#39;Content-Type: application/json; charset=utf-8&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>     -d <span class="s1">$&#39;{
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;body&#34;: &#34;已封禁:\n&#39;</span><span class="nv">$msg</span><span class="s1">&#39;&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;device_key&#34;: &#34;YOUR_DEVICE_ID&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;level&#34;: &#34;passive&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;title&#34;: &#34;IDS&#34;
</span></span></span><span class="line"><span class="cl"><span class="s1">}&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>重启rsyslog与logrotate服务使配置生效</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">systemctl restart rsyslog
</span></span><span class="line"><span class="cl">systemctl restart logrotate
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded>
    </item>
    
    <item>
      <title>iOS中国大陆工作日闹钟</title>
      <link>https://blog.9-ch.com/post/homelab-cn-working-clock/</link>
      <pubDate>Fri, 29 Apr 2022 19:22:21 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-cn-working-clock/</guid>
      <description>iOS中国大陆工作日闹钟</description>
      <content:encoded><![CDATA[<h1 id="简述">简述</h1>
<p>使用数据来自</p>
<ul>
<li>Apple 官方<a href="https://calendars.icloud.com/holidays/cn_zh.ics">中国节假日</a>日历 (半线上方案)</li>
<li><a href="https://github.com/RyoLee/cn_working_day">cn_working_day</a> 项目 (线上方案)</li>
</ul>
<p>半线上方案使用 Apple 官方中国节假日日历数据判断,不需要频繁联网同步 <strong>推荐使用</strong></p>
<p>线上方案使用 cn_working_day 数据,使用 Github action 基于<a href="https://github.com/workalendar/workalendar">workalendar</a> 自动生成近 30 天工作日信息</p>
<h1 id="已知-bug">已知 BUG</h1>
<ul>
<li>快捷指令无法操作健康添加的就寝闹钟: ios bug 待官方修复</li>
</ul>
<h1 id="半线上方案">半线上方案</h1>
<h2 id="导入设定">导入&amp;设定</h2>
<p><a href="https://www.icloud.com/shortcuts/344b8f1ec97e461d81df254e86eb490b">快捷指令-中国大陆节假日闹钟</a></p>
<p>导入后编辑快捷指令第 4/12 行,手动选择对应的闹钟并保存</p>
<p>建议检查第 2 行日历是否为<code>中国节假日</code>, 以防导入未自动匹配正确的日历</p>
<h2 id="自动化">自动化</h2>
<p>为防止快捷指令运行异常时未能开启闹钟,这里参考被动安全概念,即通过复数个自动化任务先在每天凌晨无条件开启闹钟,再通过本快捷指令判断是否为休息日关闭</p>
<p>建议在每天 <code>00:01</code> <code>00:02</code> <code>00:03</code> 添加三个自动化执行开启闹钟,再在 <code>01:00</code> <code>02:00</code> <code>03:00</code> 添加三个自动化执行本快捷指令,6 个任务均关闭运行前询问,关闭运行时通知</p>
<h1 id="线上方案">线上方案</h1>
<h2 id="导入设定-1">导入&amp;设定</h2>
<p>iOS 工作日闹钟<a href="https://www.icloud.com/shortcuts/5ff1633342da40b4951e87c8551a0aa7">快捷指令-工作日闹钟</a></p>
<p>当前版本 v1.1 已更新数据 URL</p>
<p>使用该快捷指令需配置 2 个闹钟,分别对应工作日和休息日,再编辑快捷指令找到如下部分,分别点击&quot;工作日&quot;/&ldquo;休息日&quot;改为需要的闹钟</p>
<ul>
<li>[打开]闹钟&quot;工作日&rdquo;</li>
<li>[打开]闹钟&quot;休息日&quot;</li>
</ul>
<p>因闹钟可能不存在或未配置闹钟名,[打开]闹钟可能会显示异常,请手动修改打开闹钟&quot;工作日&quot;/&ldquo;休息日&quot;为对应闹钟</p>
<p><strong>请不要修改后面的部分,后面的关闭部分除非你要删除休息日闹钟,否则不需要手动修改</strong></p>
<h2 id="不需要休息日闹钟">不需要休息日闹钟？</h2>
<p>如果休息日想睡懒觉不需要闹钟,则删除以下 2 项</p>
<ul>
<li>[打开]闹钟&quot;休息日&rdquo;</li>
<li>[关闭]闹钟&quot;休息日闹钟&quot;</li>
</ul>
<h2 id="自动化-1">自动化</h2>
<p><del>自动化可以自行选择方案,比较常见的是在 快捷指令-自动化-创建个人自动化-打开&quot;勿扰模式&quot;模式时 添加运行本快捷指令利用勿扰模式触发自动运行</del></p>
<p><del>勿扰模式在 设置-专注模式-勿扰模式-自动打开 处添加 每天 00:10-06:00 配置,即可实现全自动触发</del></p>
<p>最新版本上已支持定时无操作触发,勿扰方式是旧版的老黄历了</p>
<p>新版直接如下操作即可:</p>
<p>快捷指令&ndash;&gt;自动化&ndash;&gt;&quot;+&quot;&ndash;&gt;创建个人自动化&ndash;&gt;特定时间&ndash;&gt;修改时间(注意要在 0 点以后)并下一步&ndash;&gt;添加操作&ndash;&gt;运行快捷指令&ndash;&gt;点选运行&quot;工作日闹钟&quot;并下一步&ndash;&gt;<strong>取消勾选运行前询问</strong>&ndash;&gt;完成</p>
<p>如果没有取消勾选运行前询问则为老版本,需要继续使用勿扰来绕过</p>
<h2 id="其他">其他</h2>
<ol>
<li>首次运行时会询问是否运行访问数据源网站,需要手动允许一次才能自动运行,不然会卡住</li>
<li>可以通过添加多个自动化的方式防止访问数据源失败(如工作日/休息日闹钟分别为 07:00/09:32,可以在 1/3/5 点分别加一个)</li>
<li><strong>请求数据失败时,两个闹钟都会开启</strong></li>
</ol>
]]></content:encoded>
    </item>
    
    <item>
      <title>Gevjon -- YGO Master Duel工具</title>
      <link>https://blog.9-ch.com/post/gevjon-home/</link>
      <pubDate>Sat, 23 Apr 2022 16:00:23 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/gevjon-home/</guid>
      <description>支持识别控制器调用的卡查工具</description>
      <content:encoded><![CDATA[<p>Gevjon项目由核心(Core)与控制器(Observer)组成,核心可独立使用</p>
<p>组合使用时文件夹结构如下</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Gevjon
</span></span><span class="line"><span class="cl">├── Gevjon-Observer.pyw
</span></span><span class="line"><span class="cl">├── LICENSE
</span></span><span class="line"><span class="cl">├── README.md
</span></span><span class="line"><span class="cl">├── cards.json
</span></span><span class="line"><span class="cl">├── core
</span></span><span class="line"><span class="cl">│   ├── Gevjon.exe
</span></span><span class="line"><span class="cl">│   ├── Gevjon.exe.Config
</span></span><span class="line"><span class="cl">│   ├── README.md
</span></span><span class="line"><span class="cl">│   ├── data.json
</span></span><span class="line"><span class="cl">│   └── version.txt
</span></span><span class="line"><span class="cl">├── log.txt
</span></span><span class="line"><span class="cl">├── requirements.txt
</span></span><span class="line"><span class="cl">└── version.txt
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="core">Core</h3>
<p>本项目为Gevjon项目组件core组件,仅提供卡查功能</p>
<h4 id="界面操作">界面操作</h4>
<p>查询框输入查询内容后回车(或Ctrl+回车)进行查询,支持中日英三语(包括简中官方译名和日文ruby注音)</p>
<ul>
<li>模糊查询: Enter</li>
<li>准确查询: Ctrl+Enter</li>
</ul>
<h4 id="下载方式">下载方式</h4>
<p>本项目使用Github Actions编译发布,构建完成后会自动发布到Release与<a href="https://github.com/RyoLee/Gevjon/tree/gh-pages">gh-pages</a>分支,并更新jsDeliver缓存</p>
<p>以下4个链接正常情况下内容均一致,请在下载后检查校验和是否一致,压缩包SHA256见Release页</p>
<ul>
<li>
<p><a href="https://github.com/RyoLee/Gevjon/releases/latest">Release-Latest</a></p>
</li>
<li>
<p><a href="https://github.com/RyoLee/Gevjon/raw/gh-pages/Gevjon.7z">GH-Pages</a></p>
</li>
<li>
<p><a href="https://cdn.jsdelivr.net/gh/RyoLee/Gevjon@gh-pages/Gevjon.7z">GH-Pages-CDN-JSD*</a></p>
</li>
<li>
<p><a href="https://raw.githubusercontents.com/RyoLee/Gevjon/gh-pages/Gevjon.7z">GH-Pages-CDN-CF**</a></p>
<p><em>* jsDelivr CDN加速缓存版本,发布更新时会尝试通知更新缓存,一般与上方两个链接内容一致,但少数情况下偶尔可能被墙</em></p>
<p><em>** Cloudflare CDN加速缓存版本,可能会存在更新延迟问题,仅建议其他3种方式均无法下载时使用</em></p>
</li>
</ul>
<h4 id="第三方调用方式">第三方调用方式</h4>
<p>使用如下命名管道接收控制命令</p>
<p><code>\\.\pipe\GevjonCore</code></p>
<h4 id="控制命令格式">控制命令格式</h4>
<ul>
<li>mode: 查询模式
<ul>
<li>id: id搜索模式  //调整中</li>
<li>name: 卡名搜索模式 //调整中</li>
<li>issued: 控制器下发模式</li>
</ul>
</li>
<li>id: YGOPro版本卡片ID</li>
<li>name: 卡名,支持简单的模糊搜索,比如&quot;C107&quot;可查询到卡片&quot;混沌No.107 超银河眼时空龙&quot;</li>
<li>data: 卡片数据,仅控制器下发模式生效,使用下发模式时,不会使用内部数据生成卡名,字段类型为string,内容为</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;cid&#34;</span><span class="p">:</span> <span class="mi">11134</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">94415058</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;cn_name&#34;</span><span class="p">:</span> <span class="s2">&#34;星读之魔术师&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;cnocg_n&#34;</span><span class="p">:</span> <span class="s2">&#34;星读魔术师&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;jp_ruby&#34;</span><span class="p">:</span> <span class="s2">&#34;ほしよみのまじゅつし&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;jp_name&#34;</span><span class="p">:</span> <span class="s2">&#34;星読みの魔術師&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;en_name&#34;</span><span class="p">:</span> <span class="s2">&#34;Stargazer Magician&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nt">&#34;types&#34;</span><span class="p">:</span> <span class="s2">&#34;[怪兽|效果|灵摆] 魔法师/暗\n[★5] 1200/2400  1/1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nt">&#34;pdesc&#34;</span><span class="p">:</span> <span class="s2">&#34;①：自己的灵摆怪兽进行战斗的场合，对方直到伤害步骤结束时魔法卡不能发动。\n②：另一边的自己的灵摆区域没有「魔术师」卡或者「异色眼」卡存在的场合，这张卡的灵摆刻度变成4。&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nt">&#34;desc&#34;</span><span class="p">:</span> <span class="s2">&#34;①：1回合1次，只让自己场上的灵摆怪兽1只因对方的效果回到自己手卡时才能发动。那1只同名怪兽从手卡特殊召唤。&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>可使用项目目录下PipeClient.py进行测试,请注意json需转义</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="p">.\</span><span class="n">PipeClient</span><span class="p">.</span><span class="py">py</span> <span class="s2">&#34;{\&#34;</span><span class="n">id</span><span class="p">\</span><span class="s2">&#34;:\&#34;</span><span class="p">\</span><span class="s2">&#34;,\&#34;</span><span class="n">name</span><span class="p">\</span><span class="s2">&#34;:\&#34;</span><span class="mf">107</span><span class="p">\</span><span class="s2">&#34;,\&#34;</span><span class="n">mode</span><span class="p">\</span><span class="s2">&#34;:\&#34;</span><span class="n">name</span><span class="p">\</span><span class="s2">&#34;}&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h4 id="数据更新">数据更新</h4>
<p><del>数据来源为<a href="https://github.com/mycard/ygopro-database">mycard/ygopro-database (github.com)</a>,后续更新请自行下载，将locales文件夹拖放到DB/Cover.py脚本上生成data.json数据文件</del></p>
<p>v1.3.0以后版本数据来源为<a href="https://ygocdb.com/">百鸽</a>, <del>由于该来源api暂未提供版本跟踪相关信息,暂不提供自动更新检查(后续视情况增加),</del> 已支持自动更新,感谢<a href="https://github.com/mercury233">@mercury233</a></p>
<h3 id="控制器">控制器</h3>
<p>项目见 <a href="https://github.com/RyoLee/Gevjon-Observer">Gevjon-Observer</a></p>
<p>不同分支对应不同实现，以分支Readme文档为准</p>
<h4 id="python-内存读取实现">Python 内存读取实现</h4>
<p>本分支为Python内存读取实现</p>
<p>基于<a href="https://github.com/SkywalkerJi/mdt">SkywalkerJi/mdt: Yu-Gi-Oh! Master Duel (github.com)</a></p>
<p><del>请下载<a href="https://github.com/RyoLee/Gevjon/">RyoLee/Gevjon</a>并解压至core文件夹后,直接启动控制器(Gevjon-Observer.pyw)即可,核心会自动启动</del></p>
<p>当前版本Release已打包core</p>
<h3 id="风险声明">风险声明</h3>
<p>本程序(Gevjon-Core)仅提供游戏王卡片查询功能,独立运行时与游戏无关,纯手动输入0风险</p>
<p>至于外接了其他控制器的情况,那要看控制器是怎么实现的了,例如控制器使用OCR实现,相对内存读取实现风险会低很多(因为特征上来看和主播开OBS直播是类似的的),但是也不是0风险</p>
<p>不管是基于内存读取还是图像识别/OCR,<strong>本质都是违反K社ToS的第三方软件</strong>,因为K社官方并没有发布任何API接口或SDK(以及配套的许可文档)允许第三方开发类似的工具</p>
<p><strong>理论上检测很容易,不要以为只读不写/或者截图就安全,如果想查,反作弊程序给相关API下点钩子就能查,甚至暴力一点的会不管你的隐私信息直接用进程名的黑名单查(如TP之流)</strong></p>
<p>实际上K社管不管那100%是他们内部决定的,只不过目前这个时间点他们没管,参考DL的经验他们可能也懒得管这种非恶意利用</p>
<p><strong>总之,风险自负</strong></p>
<h3 id="license">License</h3>
<p><a href="https://github.com/RyoLee/Gevjon/blob/master/LICENSE">MIT License</a></p>
]]></content:encoded>
    </item>
    
    <item>
      <title>RouterOS 通过 OSPF IP分流至 OpenWrt</title>
      <link>https://blog.9-ch.com/post/homelab-ros-ospf/</link>
      <pubDate>Wed, 20 Apr 2022 17:59:11 +0800</pubDate>
      
      <guid>https://blog.9-ch.com/post/homelab-ros-ospf/</guid>
      <description>ROS ip 分流方案</description>
      <content:encoded><![CDATA[<h3 id="更新">更新</h3>
<ul>
<li>2022-05-17 修改后的方案(带配置) <a href="https://blog.9-ch.com/post/homelab-no-cn-routes/">RouterOS 通过 OSPF IP分流非CN流量</a></li>
</ul>
<h3 id="组网参考">组网参考</h3>
<p>Reflist:</p>
<ul>
<li><a href="https://www.truenasscale.com/2021/12/13/195.html">使用RouterOS，OSPF 和OpenWRT给国内外 IP 分流</a></li>
<li><a href="https://www.kn1f4.com/news/767.html">RouterOS路由OSPF协议+树莓派分流国外流量</a></li>
</ul>
<p>主要适用于不想折腾PS/XBOX/Switch设备网关配置,又不希望出口网关为卵漏油/AIB的,或者怕折腾网络时家里断网影响家人的</p>
<p>遇到一些问题记录一下</p>
<h3 id="ros-ddns失效">ROS DDNS失效</h3>
<p>表现: 域名解析ip不正确</p>
<p>原因: 分流后ROS内置ip cloud(DDNS)流量同样会被指向OpenWrt导致错误,尝试打标签bypass对应udp流量未成功,因为有公网IP所以直接改为通过域名服务商API更新对应解析为PPPOE接口地址</p>
<p>解决: 修改以下脚本中&quot;CloudFlare variables&quot;段内容即可.原始脚本见<a href="https://github.com/mike6715b/Mikrotik_CF_DDNS">Mikrotik_CF_DDNS</a></p>
<details>
  <summary>Cloudflare DDNS ROS脚本(IPV4)</summary>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">#########################################################################
</span></span><span class="line"><span class="cl">#         ==================================================            #
</span></span><span class="line"><span class="cl">#         $ Mikrotik RouterOS update script for CloudFlare $            #
</span></span><span class="line"><span class="cl">#         ==================================================            #
</span></span><span class="line"><span class="cl">#                                                                       #
</span></span><span class="line"><span class="cl"># - You need a CloudFlare account &amp; api key (look under settings),      #
</span></span><span class="line"><span class="cl">#   a zone and A record in it                                           #
</span></span><span class="line"><span class="cl"># - All variables in first section are obvious,                         #
</span></span><span class="line"><span class="cl">#   except CFid and CFzoneid                                            #
</span></span><span class="line"><span class="cl"># - Obtain CFzoneid from Cloudflare Dashboard,                          #
</span></span><span class="line"><span class="cl">#   on Overview tab scroll down                                         # 
</span></span><span class="line"><span class="cl">#   To obtain CFid use following command in any unix shell:             #
</span></span><span class="line"><span class="cl">#    curl -X GET &#34;https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/dns_records?name=YOUR_DOMAIN&#34; -H &#34;Authorization:Bearer $CFtkn&#34; -H &#34;Content-Type: application/json&#34; | python -mjson.tool
</span></span><span class="line"><span class="cl"># - You can use my Postman script to get those variables                #
</span></span><span class="line"><span class="cl"># - Enable CFDebug if needed - it&#39;ll print some info to logs            #
</span></span><span class="line"><span class="cl"># - Enable CFcloud if you don&#39;t get a public IP on interface            #
</span></span><span class="line"><span class="cl"># - Put script under /system scripts giving &#34;read,write,ftp&#34; policy access.       #
</span></span><span class="line"><span class="cl">#   For 6.29 and older &#34;test&#34; policy is also needed.                    #
</span></span><span class="line"><span class="cl"># - Add script to /system scheduler using it&#39;s name in &#34;on-event&#34;       #
</span></span><span class="line"><span class="cl"># - Requires at least RouterOS 6.44beta75 for multiple header support   #
</span></span><span class="line"><span class="cl">#                                                                       #
</span></span><span class="line"><span class="cl">#              Credits for Samuel Tegenfeldt, CC BY-SA 3.0              #
</span></span><span class="line"><span class="cl">#                        Modified by kiler129                           #
</span></span><span class="line"><span class="cl">#                        Modified by viritt                             #
</span></span><span class="line"><span class="cl">#                        Modified by asuna                              #
</span></span><span class="line"><span class="cl">#                        Modified by mike6715b                          #
</span></span><span class="line"><span class="cl">#                                                                       #
</span></span><span class="line"><span class="cl">#               Tested and working as of February 22, 2021              #
</span></span><span class="line"><span class="cl">#########################################################################
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">################# CloudFlare variables #################
</span></span><span class="line"><span class="cl">:local CFDebug &#34;false&#34;
</span></span><span class="line"><span class="cl">:local CFcloud &#34;false&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:global WANInterface &#34;[YOUR_WAN_INTERFACE_NAME]&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:local CFdomain &#34;[YOUR_DOMAIN]&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:local CFtkn &#34;[YOUR_CF_TOKEN]&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:local CFzoneid &#34;[YOUR_CF_ZONE_ID]&#34;
</span></span><span class="line"><span class="cl">:local CFid &#34;[YOUR_CF_ID]&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:local CFrecordType &#34;&#34;
</span></span><span class="line"><span class="cl">:set CFrecordType &#34;A&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:local CFrecordTTL &#34;&#34;
</span></span><span class="line"><span class="cl">:set CFrecordTTL &#34;60&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">#########################################################################
</span></span><span class="line"><span class="cl">########################  DO NOT EDIT BELOW  ############################
</span></span><span class="line"><span class="cl">#########################################################################
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:log info &#34;Updating $CFDomain ...&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">################# Internal variables #################
</span></span><span class="line"><span class="cl">:local previousIP &#34;&#34;
</span></span><span class="line"><span class="cl">:global WANip &#34;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">################# Build CF API Url (v4) #################
</span></span><span class="line"><span class="cl">:local CFurl &#34;https://api.cloudflare.com/client/v4/zones/&#34;
</span></span><span class="line"><span class="cl">:set CFurl ($CFurl . &#34;$CFzoneid/dns_records/$CFid&#34;);
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">################# Get or set previous IP-variables #################
</span></span><span class="line"><span class="cl">:if ($CFcloud = &#34;true&#34;) do={
</span></span><span class="line"><span class="cl">    :set WANip [/ip cloud get public-address]
</span></span><span class="line"><span class="cl">};
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:if ($CFcloud = &#34;false&#34;) do={
</span></span><span class="line"><span class="cl">    :local currentIP [/ip address get [/ip address find interface=$WANInterface ] address];
</span></span><span class="line"><span class="cl">    :set WANip [:pick $currentIP 0 [:find $currentIP &#34;/&#34;]];
</span></span><span class="line"><span class="cl">};
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">:if ([/file find name=ddns.tmp.txt] = &#34;&#34;) do={
</span></span><span class="line"><span class="cl">    :log error &#34;No previous ip address file found, createing...&#34;
</span></span><span class="line"><span class="cl">    :set previousIP $WANip;
</span></span><span class="line"><span class="cl">    :execute script=&#34;:put $WANip&#34; file=&#34;ddns.tmp&#34;;
</span></span><span class="line"><span class="cl">    :log info (&#34;CF: Updating CF, setting $CFDomain = $WANip&#34;)
</span></span><span class="line"><span class="cl">    /tool fetch http-method=put mode=https output=none url=&#34;$CFurl&#34; http-header-field=&#34;Authorization:Bearer $CFtkn,content-type:application/json&#34; http-data=&#34;{\&#34;type\&#34;:\&#34;$CFrecordType\&#34;,\&#34;name\&#34;:\&#34;$CFdomain\&#34;,\&#34;ttl\&#34;:$CFrecordTTL,\&#34;content\&#34;:\&#34;$WANip\&#34;}&#34;
</span></span><span class="line"><span class="cl">    :error message=&#34;No previous ip address file found.&#34;
</span></span><span class="line"><span class="cl">} else={
</span></span><span class="line"><span class="cl">    :if ( [/file get [/file find name=ddns.tmp.txt] size] &gt; 0 ) do={ 
</span></span><span class="line"><span class="cl">    :global content [/file get [/file find name=&#34;ddns.tmp.txt&#34;] contents] ;
</span></span><span class="line"><span class="cl">    :global contentLen [ :len $content ] ;  
</span></span><span class="line"><span class="cl">    :global lineEnd 0;
</span></span><span class="line"><span class="cl">    :global line &#34;&#34;;
</span></span><span class="line"><span class="cl">    :global lastEnd 0;   
</span></span><span class="line"><span class="cl">            :set lineEnd [:find $content &#34;\n&#34; $lastEnd ] ;
</span></span><span class="line"><span class="cl">            :set line [:pick $content $lastEnd $lineEnd] ;
</span></span><span class="line"><span class="cl">            :set lastEnd ( $lineEnd + 1 ) ;   
</span></span><span class="line"><span class="cl">            :if ( [:pick $line 0 1] != &#34;#&#34; ) do={   
</span></span><span class="line"><span class="cl">                #:local previousIP [:pick $line 0 $lineEnd ]
</span></span><span class="line"><span class="cl">                :set previousIP [:pick $line 0 $lineEnd ];
</span></span><span class="line"><span class="cl">                :set previousIP [:pick $previousIP 0 [:find $previousIP &#34;\r&#34;]];
</span></span><span class="line"><span class="cl">            }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">######## Write debug info to log #################
</span></span><span class="line"><span class="cl">:if ($CFDebug = &#34;true&#34;) do={
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: hostname = $CFdomain&#34;)
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: previousIP = $previousIP&#34;)
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: currentIP = $currentIP&#34;)
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: WANip = $WANip&#34;)
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: CFurl = $CFurl&amp;content=$WANip&#34;)
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: Command = \&#34;/tool fetch http-method=put mode=https url=\&#34;$CFurl\&#34; http-header-field=&#34;Authorization:Bearer $CFtkn,content-type:application/json&#34; output=none http-data=\&#34;{\&#34;type\&#34;:\&#34;$CFrecordType\&#34;,\&#34;name\&#34;:\&#34;$CFdomain\&#34;,\&#34;ttl\&#34;:$CFrecordTTL,\&#34;content\&#34;:\&#34;$WANip\&#34;}\&#34;&#34;)
</span></span><span class="line"><span class="cl">};
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">######## Compare and update CF if necessary #####
</span></span><span class="line"><span class="cl">:if ($previousIP != $WANip) do={
</span></span><span class="line"><span class="cl"> :log info (&#34;CF: Updating CF, setting $CFDomain = $WANip&#34;)
</span></span><span class="line"><span class="cl"> /tool fetch http-method=put mode=https url=&#34;$CFurl&#34; http-header-field=&#34;Authorization:Bearer $CFtkn,content-type:application/json&#34; output=none http-data=&#34;{\&#34;type\&#34;:\&#34;$CFrecordType\&#34;,\&#34;name\&#34;:\&#34;$CFdomain\&#34;,\&#34;ttl\&#34;:$CFrecordTTL,\&#34;content\&#34;:\&#34;$WANip\&#34;}&#34;
</span></span><span class="line"><span class="cl"> /ip dns cache flush
</span></span><span class="line"><span class="cl">    :if ( [/file get [/file find name=ddns.tmp.txt] size] &gt; 0 ) do={
</span></span><span class="line"><span class="cl">        /file remove ddns.tmp.txt
</span></span><span class="line"><span class="cl">        :execute script=&#34;:put $WANip&#34; file=&#34;ddns.tmp&#34;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">} else={
</span></span><span class="line"><span class="cl"> :log info &#34;CF: No Update Needed!&#34;
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div></details>
<h3 id="tcp流量握手缓慢">TCP流量握手缓慢</h3>
<p>表现: 访问网站时打开缓慢,F12查看SSL阶段时间长度接近甚至超过10秒</p>
<p>原因: OP与ROS在同一网段,进出流量路由不对称,触发ROS防火墙动作</p>
<p>解决: 禁用ROS防火墙drop invalid规则(位于ip-firewall-filter rules)</p>
<h3 id="icmpping异常">ICMP(Ping)异常</h3>
<p>表现: ping 被分流网段ip时黑洞</p>
<p>原因: 出口Op通过TProxy只能处理TCP/UDP流量</p>
<p>解决:</p>
<ul>
<li>A: Op添加 ICMP劫持(假响应,可规避一些软件的报错)</li>
<li>B: ROS给ICMP流量打上bypass的route标签,再创建一个bypass路由表,该表不包含OSPF宣告的分流规则,所以如果没有被ISP之类的劫持就是裸连的真响应</li>
</ul>
<h3 id="openwrt无法与被分流网段通信循环">Openwrt无法与被分流网段通信(循环)</h3>
<p>表现: OpenWrt与被分流网段通信时不通</p>
<p>原因: ROS接到宣告的表后循环Op-&gt;ROS-&gt;Op-&gt;&hellip;</p>
<p>解决: 给Op流量打上标签,直接走bypass表</p>
<p>防火墙规则(Mangle)可参考</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">chain=prerouting action=mark-routing new-routing-mark=bypass passthrough=yes src-address=[BYPASS_DEVICE_IP] dst-address-list=!private log=no log-prefix=&#34;&#34;
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="dns-cdn优化">DNS CDN优化</h3>
<p>表现: 不需要分流区域域名CDN解析为分流区域</p>
<p>原因: Op全局流量隧道,DNS解析也被隧道处理,导致CDN失效</p>
<p>解决: dnsmasq-full分流list外走国内DNS服务,list内走DoH,Op故障时回落全国内DNS服务</p>
<h3 id="openwrt访问内网异常">OpenWrt访问内网异常</h3>
<p>表现: Op所在子网广播域外的其他子网访问Op时,无法正常响应</p>
<p>原因: Op走了bypass表,未添加其他子网路由,下一跳直接从pppoe-out出去了</p>
<p>解决: 防火墙匹配src address为op的ip,dst address为需要支持访问子网流量打上main标签走main路由表</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
