dieyushi's Blog
2017-01-28T17:35:01+08:00
https://www.zzsec.org/
dieyushi
zz@zzsec.org
网络编程的一些个人总结
2015-10-03T18:01:02+08:00
https://www.zzsec.org/2015/10/network-programming-summary
<p>下面是一些工作学习中总结的网络编程的方法。顺便提一句,又是一年没更新博客了,时间过的真快。</p>
<ul>
<li>一些手册一定要好好读一下,比如 proc(5), capabilities(7), icmp(7), ipv6(7), netlink(7), raw(7), socket(7), tcp(7), udp(7)</li>
<li>epoll 或者 select 处理事件时,可读事件时,read返回值-1,如果errno不为EAGAIN,可以认为失败,并关闭fd。read返回0,说明对方断开连接,此时也需要关闭fd。如果链路断了,如拔掉网线,需要是用keepalive来触发可写事件</li>
</ul>
<!--more-->
<ul>
<li>本地UDP发送过快也是会丢包的。非阻塞情况下的unix domain socket哪怕是STREAM的也是会丢包的</li>
<li>使用unix socket的一个linux专属技巧是abstract pathname,系统会自动管理sock path,详见man 7 unix,经测试使用的缺点为如果程序segment fault等原因崩溃,地址不会自动释放。下次绑定就会失败</li>
<li>使用unix socket通信相比于本地udp通信减少了校验和的计算。使用阻塞函数时,unix domain socket可以保证不丢包不乱序,但是当发送缓冲区满了的话则会阻塞。使用非阻塞操作时经测试会丢包</li>
<li>使用setsockopt设置发送缓冲时,SO_RCVBUF和SO_SNDBUF的最大值受系统设置限制(man 7 socket)。可以使用SO_RCVBUFFORCE和SO_SNDBUFFORCE来无视系统设置</li>
<li>SIGPIPE信号,网络编程时一定要处理该信号。同样一般要设置的还有SO_REUSEADDR。当客户端close连接时,若server继续发送数据,会收到RST,继续写就会SIGPIPE</li>
<li>Consider two peers, A and B, communicating via TCP. If B closes a socket and there is any data in B’s receive queue, B sends a TCP RST to A instead of following the standard TCP closing protocol, resulting in an ECONNRESET error return value from recv( )</li>
<li>网络编程对事件进行封装,提供注册回调函数,在可读、可写时进行函数调用。一般用法,针对非阻塞情况,初始化时将可读事件注册,需要写的时候先写,写不下去的时候(errno=EAGAIN)再挂上可写事件,只要发送缓冲区还有空间,就是可写的</li>
<li>基于事件的编程框架,需要记录最后一次成功read或write的时间,如果idletime大于阈值,直接close</li>
<li>服务器编程可以设置最大的fd个数,然后一次性申请FileEvent数组,之后由fd到事件查询代价O(1)</li>
<li>针对非阻塞socket,connect返回EINPROGRESS时需要将fd加到可写事件监视集合中,当select()或者poll()返回可写事件时,需要用getsockopt去读SOL_SOCKET层面的SO_ERROR选项,SO_ERROR为0表示连接成功,否则为连接失败</li>
<li>epoll ET模式的处理方式。读:只要可读就一直读,一直读到返回0,或者error = EAGAIN。写:只要可写就一直写,知道数据发送完,或者errno = EAGAIN</li>
<li>socket read缓冲区最大值TCP可查看”/proc/sys/net/ipv4/tcp_rmem”, udp 65536</li>
<li>实现定时器时通常办法是select/poll/epoll接口,精度毫秒级;还有就是新增的系统调用timerfd_create 把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,高于poll的精度</li>
<li>在主动关闭连接时,可以先shutdown(fd, SHUT_WR)关闭写端,等对方close时再关闭读端。这样子的好处是如果对方已经发送了一些数据,这些数据不会漏收。这就要求对端在read返回0之后关闭连接或者shutdown写端</li>
<li>网络编程一种比较好的模型是“one loop per thread”,如果事件库不是线程安全的,则需要使用pipe或者</li>
<li>socketpair通知,子线程接受到通知(fd可读)后处理,kernel 2.6.22加入了eventfd,是更好的通知方法</li>
<li>TCP Nagle算法和TCP Delayed Ack机制可能会导致网络延时(Linux 40ms, Windows 200ms),最容易产生问题的就是"Write-Write-Read”这种模型,发送端的Nagle算法和接收端的Delayed Ack会导致一直等到接收端delayed ack超时后数据才发送出去</li>
<li>accept返回EMFILE,进程描述符用完了,无法创建新的socket,也无法close连接,会导致不断通知该可读事件,程序busy loop,cpu 100%,解决方法是事先准备一个nullfd=open(“/dev/null”),close该fd,accept,close socket,然后再nullfd=open(“/dev/null”),缺点是该方法线程不安全,多线程accept可能导致nullfd用于新socket创建,然后又处于busy loop中</li>
<li>关注下signalfd(2.6.22+),eventfd(2.6.22+),timerfd(2.6.25+),分别可以做信号通知、事件通知和定时器,都可以select/poll/epoll,有事件发生时fd可读</li>
<li>清除不活跃的socket,使用定时器在处理大量连接时会很低效,可以采用timing wheel算法进行处理</li>
<li>在高并发的情况下,系统的fd数目可能是瓶颈,系统统一限制为/proc/sys/fs/file-max,该值的默认大小为内存总数/10k(fs/file_table.c)</li>
</ul>
ip2dec, dec2ip, ip2hex and hex2ip
2014-10-19T02:46:24+08:00
https://www.zzsec.org/2014/10/ip2dec-dec2ip-ip2hex-and-hex2ip
<p>写程序时经常会因为偷懒在syslog里面直接打10进制或者16进制的ip地址,又或者是数据库中保存的不是ip字符串,当看这些数据时每次都需要手算一些。为了提高效率,写了四个脚本,放到PATH里面就可以执行了。</p>
<div class="highlight"><pre><code class="language-sh" data-lang="sh"><span></span><span class="ch">#!/bin/bash</span>
ip2hex <span class="o">()</span> <span class="o">{</span>
<span class="nb">local</span> a b c d <span class="nv">ip</span><span class="o">=</span><span class="nv">$@</span>
<span class="nv">IFS</span><span class="o">=</span>. <span class="nb">read</span> -r a b c d <span class="o"><<<</span> <span class="s2">"</span><span class="nv">$ip</span><span class="s2">"</span>
<span class="nb">printf</span> <span class="s1">'0x%x\n'</span> <span class="s2">"</span><span class="k">$((</span>a <span class="o">*</span> <span class="m">256</span> <span class="o">**</span> <span class="m">3</span> <span class="o">+</span> b <span class="o">*</span> <span class="m">256</span> <span class="o">**</span> <span class="m">2</span> <span class="o">+</span> c <span class="o">*</span> <span class="m">256</span> <span class="o">+</span> d<span class="k">))</span><span class="s2">"</span>
<span class="o">}</span>
ip2hex <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</code></pre></div><div class="highlight"><pre><code class="language-sh" data-lang="sh"><span></span><span class="ch">#!/bin/bash</span>
hex2ip <span class="o">()</span> <span class="o">{</span>
<span class="nb">local</span> ip <span class="nv">dec</span><span class="o">=</span><span class="nv">$@</span>
<span class="nv">desc</span><span class="o">=</span><span class="k">$((</span><span class="nv">$desc</span><span class="k">))</span>
<span class="k">for</span> e in <span class="o">{</span><span class="m">3</span>..0<span class="o">}</span>
<span class="k">do</span>
<span class="o">((</span><span class="nv">octet</span> <span class="o">=</span> dec / <span class="o">(</span><span class="m">256</span> ** e<span class="o">)</span> <span class="o">))</span>
<span class="o">((</span>dec -<span class="o">=</span> octet * <span class="m">256</span> ** e<span class="o">))</span>
<span class="nv">ip</span><span class="o">+=</span><span class="nv">$delim$octet</span>
<span class="nv">delim</span><span class="o">=</span>.
<span class="k">done</span>
<span class="nb">printf</span> <span class="s1">'%s\n'</span> <span class="s2">"</span><span class="nv">$ip</span><span class="s2">"</span>
<span class="o">}</span>
hex2ip <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</code></pre></div><div class="highlight"><pre><code class="language-sh" data-lang="sh"><span></span><span class="ch">#!/bin/bash</span>
ip2dec <span class="o">()</span> <span class="o">{</span>
<span class="nb">local</span> a b c d <span class="nv">ip</span><span class="o">=</span><span class="nv">$@</span>
<span class="nv">IFS</span><span class="o">=</span>. <span class="nb">read</span> -r a b c d <span class="o"><<<</span> <span class="s2">"</span><span class="nv">$ip</span><span class="s2">"</span>
<span class="nb">printf</span> <span class="s1">'%d\n'</span> <span class="s2">"</span><span class="k">$((</span>a <span class="o">*</span> <span class="m">256</span> <span class="o">**</span> <span class="m">3</span> <span class="o">+</span> b <span class="o">*</span> <span class="m">256</span> <span class="o">**</span> <span class="m">2</span> <span class="o">+</span> c <span class="o">*</span> <span class="m">256</span> <span class="o">+</span> d<span class="k">))</span><span class="s2">"</span>
<span class="o">}</span>
ip2dec <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</code></pre></div><div class="highlight"><pre><code class="language-sh" data-lang="sh"><span></span><span class="ch">#!/bin/bash</span>
dec2ip <span class="o">()</span> <span class="o">{</span>
<span class="nb">local</span> ip <span class="nv">dec</span><span class="o">=</span><span class="nv">$@</span>
<span class="k">for</span> e in <span class="o">{</span><span class="m">3</span>..0<span class="o">}</span>
<span class="k">do</span>
<span class="o">((</span><span class="nv">octet</span> <span class="o">=</span> dec / <span class="o">(</span><span class="m">256</span> ** e<span class="o">)</span> <span class="o">))</span>
<span class="o">((</span>dec -<span class="o">=</span> octet * <span class="m">256</span> ** e<span class="o">))</span>
<span class="nv">ip</span><span class="o">+=</span><span class="nv">$delim$octet</span>
<span class="nv">delim</span><span class="o">=</span>.
<span class="k">done</span>
<span class="nb">printf</span> <span class="s1">'%s\n'</span> <span class="s2">"</span><span class="nv">$ip</span><span class="s2">"</span>
<span class="o">}</span>
dec2ip <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span>
</code></pre></div>
<p>测试</p>
<div class="highlight"><pre><code class="language-sh" data-lang="sh"><span></span><span class="c1"># ip2hex 1.2.3.4| xargs hex2ip | xargs ip2dec | xargs dec2ip</span>
<span class="m">100</span>.101.102.103
</code></pre></div>
cpuid使用中的一个注意事项
2014-10-12T13:49:22+08:00
https://www.zzsec.org/2014/10/cpuid-register-clobbering
<p>针对特定CPU进行一些优化工作时,就需要先对CPU支持的指令集进行判断。一般的做法是使用cpuid指令,然后检查相应的标识位来判断。这部分详见Intel的手册。</p>
<p>在使用中,发现了一个诡异的问题,如果在程序初始化时调用封装了cpuid的函数则正常运行,但是如果每次在使用使用优化函数前调用cpuid则会发生段错误。</p>
<p>挂上gdb启动程序,然后在段错误前si逐指令跟踪。最终确定原因为cpuid会将结果保存到RAX,RBX,RCX,RDX,问题就出到RBX上,根据<a href="https://software.intel.com/en-us/articles/introduction-to-x64-assembly">Intel的文章</a>,</p>
<blockquote>
<ul>
<li>Registers RAX, RCX, RDX, R8, R9, R10, and R11 are considered volatile and must be considered destroyed on function calls.</li>
<li>RBX, RBP, RDI, RSI, R12, R14, R14, and R15 must be saved in any function using them.</li>
</ul>
</blockquote>
<p>如果gcc产生的指令使用到了RBX,我们又没有对RBX进行单独的保护,就会出现段错误。正确的调用cpuid方法是在使用cpuid前将RBX寄存器的值保存一下。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span> movq %rbx, %r8
movl $1, %eax
cpuid
xchgq %rbx, %r8
</code></pre></div>
linux kernel module version check
2014-10-11T00:34:14+08:00
https://www.zzsec.org/2014/10/linux-kernel-module-version-check
<p>关于Linux内核模块加载时的版本检查,看了一些资料,记录一下。原文地址:<a href="http://www.skynet.ie/%7Emark/home/kernel/symbols.html">http://www.skynet.ie/~mark/home/kernel/symbols.html</a></p>
<h3 id="exporting-symbols">Exporting Symbols</h3>
<p>By default, any global variables or functions defined in a module are exported to the kernel symbol table when the module is loaded. However, there are ways which you may control which symbols are exported.</p>
<p>If you only require that none of the module's symbols are exported you can use the EXPORT_NO_SYMBOLS macro.</p>
<p>If however, you require that only some of your global symbols are exported you will need to use the EXPORT_SYMBOL macro to export it. If CONFIG_MODVERSIONS is turned on a further step is required in the build process, but that will be explained later.</p>
<h3 id="so-how-does-this-work">So How Does This Work?</h3>
<p>A kernel module that explicitly exports symbols will have two special sections in its object file: the symbol table '__ksymtab' and the string table '.kstrtab'. When a symbol is exported by a module using EXPORT_SYMBOL, two things happen:</p>
<blockquote>
<ul>
<li><p>a string, that is either the symbol name or, in the case that CONFIG_MODVERSIONS is turned on, the symbol name with some extra versioning info attached, is defined in the string table.</p></li>
<li><p>a module_symbol structure is defined in the symbol table. This structure contains a pointer to the symbol itself and a pointer to the entry in the string table.</p></li>
</ul>
</blockquote>
<p>When a module is loaded this info is added to the kernels symbol table and these symbols are now treated like any of the kernel's exported symbols.</p>
<p>To take a peek at your module's symbol table do</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>$> objdump --disassemble -j __ksymtab sunrpc.o
</code></pre></div>
<p>or the string table do</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>$> objdump --disassemble -j .kstrtab sunrpc.o
</code></pre></div>
<h3 id="config_modversions-et-al">CONFIG_MODVERSIONS et al.</h3>
<p>CONFIG_MODVERSIONS is a notion thought up to make people's lives easier. In essence, what it is meant to achieve is that if you have a module you can attempt to load that module into any kernel, safe in the knowledge that it will fail to load if any of the kernel data structures, types or functions that the module uses have changed.</p>
<p>If your kernel is not compiled with CONFIG_MODVERSIONS enabled you will only be able to load modules that were compiled specifically for that kernel version and that were also compiled without MODVERSIONS enabled.</p>
<p>However, if your kernel is compiled with CONFIG_MODVERSIONS enabled you will be able to load a module that was compiled for the same kernel version with MODVERSIONS turned off. But - here's the important part folks - you will also be able to load any modules compiled with MDOVERSIONS turned on, as long as the kernel API that the module uses hasn't changed.</p>
<h3 id="so-how-does-this-work">So How Does This Work?</h3>
<p>When CONFIG_MODVERSIONS is turned on the kernel then a special piece of versioning info is appended to every symbol exported using EXPORT_SYMBOL.</p>
<p>This versioning info is calculated using the genksyms command whose man page has this to say about how the info is calculated :</p>
<blockquote>
<p>When a symbol table is found in the source, the symbol will be expanded to its full definition, where all struct's, unions, enums and typedefs will be expanded down to their basic part, recursively. This final string will then be used as input to a CRC algorithm that will give an integer that will change as soon as any of the included definitions changes, for this symbol.</p>
<p>The version information in the kernel normally looks like: symbol_R12345678, where 12345678 is the hexadecimal representation of the CRC. representation of the CRC.</p>
</blockquote>
<p>What this means is that the versioning info is calculated in such way as that it will only change when the definition of that symbol changes.</p>
<p>The versioning string is 'appended' by the use of a #define in linux/modversions.h for every exported symbol. The #define usually winds up looking something like this (simplified):</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>#define printk printk_R1b7d4074
</code></pre></div>
<p>What this does is effectively get rid of the function 'printk' - alas, poor printk - and replace it with the much more handsome 'printk_R1b7d4074'.</p>
<p>If you have a look at linux/modversions.h you'll notice that it just includes loads of .ver files. These are generated using a command similar to</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>$> gcc -E -D__GENKSYMS__ ${c-file} | genksyms -k ${kernel-ver} > ${ver-file}
</code></pre></div>
<p>Notice that the c file if first passed through the c preprocessor before being passed to genksyms. This is to collapse all macros and stuff beforehand.</p>
<h3 id="what-does-this-mean-for-modules">What does this mean for modules?</h3>
<p>When modules are being compiled for a kernel with CONFIG_MODVERSIONS turned on, the header file linux/modversions.h must be included at the top of every c file. This you be an awful pain to do, so we just do it with the gcc flag '-include'.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span> ifdef CONFIG_MODULES
ifdef CONFIG_MODVERSIONS
MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h
endif
</code></pre></div>
<p>The extra MODVERSIONS flag is used to indicate that this is a module being compiled with CONFIG_MODVERSIONS turned on as opposed to the kernel being compiled with CONFIG_MODVERSIONS enabled.</p>
gdb常用的一些技巧
2014-09-21T17:48:53+08:00
https://www.zzsec.org/2014/09/some-gdb-tips-and-tricks
<p>最近一段时间遇到了几个定位了很长时间的bug,在定位过程中逐步学习了使用gdb,下面就是在调试中常用的一些调试方法。</p>
<h3 id="1">1.条件断点</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>在for或者while中想要断在特定的值处, 人工不停的continue肯定是不现实的,这时就可以使用break if。
</code></pre></div>
<h3 id="2-command">2. command</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>command可以设置在断点后执行一组gdb命令。
</code></pre></div>
<!--more-->
<h3 id="3-display">3. display</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>在单步执行时,每次执行完语句后都会显示display设置的表达式以及表达式的值。
</code></pre></div>
<h3 id="4-gdb-p">4. gdb -p</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>调试一个已经在运行中的进程。也可以gdb at。
</code></pre></div>
<h3 id="5">5. 反汇编</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>查看当前执行的汇编指令。display /5i $rip
</code></pre></div>
<h3 id="6">6. 多线程</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>info thread 查看当前进程的线程。
thread <ID> 切换到线程id为<ID>的线程。
set scheduler-locking off|on|step 设置调试线程时其它线程是否执行。
</code></pre></div>
<h3 id="7-backstrace">7. backstrace</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>查看当前函数的调用栈信息,使用frame可以切换到相应的frame。
</code></pre></div>
<h3 id="8-checkpoint">8. checkpoint</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>checkpoint是程序在那一刻的快照,当我们发现错过了某个调试机会时,可以使用restart再次回到checkpoint保存的那个程序状态。
</code></pre></div>
<h3 id="9-gcore">9. gcore</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>gdb中可以调用gcore生成coredump。
</code></pre></div>
<h3 id="10-layout">10. layout</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>layout可以让我们一边查看源代码,反汇编一边调试程序。
</code></pre></div>
<h3 id="11-watch">11. watch</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>当表达式的值发生改变时程序会停止运行。
</code></pre></div>
<h3 id="12-others">12. others</h3>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>pstack脚本打印进程所有线程的调用栈。
</code></pre></div>
表达式语法分析
2014-04-06T22:00:44+08:00
https://www.zzsec.org/2014/04/expression-parser
<h3 id="part-654280cbc50">前言</h3>
<p>用过libpcap的程序员一定会注意到libpcap在获取数据包时允许设置过滤规则,例如<code>port 80</code>表示只获取HTTP流量。但这是怎么实现的呢?我们用简单的例子来说明。在例子之前,要先介绍待会要用到的<code>flex</code>和<code>bison</code>。</p>
<h3 id="flex-bison">flex/bison</h3>
<p>flex和bison主要是为编译器和解释器的编程人员特别设计的工具,不过它们在其他领域也非常有用,因此也吸引了很多非编译器编程人员的注意。任何程序只要在输入中可以找到特定的模式,或者使用命令语言作为输入,都适合使用flex和bison。</p>
<!--more-->
<p>flex和bison是lex和yacc的GNU版本。flex用于词法分析,bison用于语法分析。简单来说,词法分析把输入分割成一个个有意义的词块,语法分析则确定这些词块是怎么关联的。举个C语言的例子:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>a = b + c;
</code></pre></div>
<p>词法分析器把代码分解为一个个的记号,a、等号、b、加号、c和分号;语法分析器则确定b+c是一个表达式,表达式的值被赋给了a。</p>
<h3 id="part-29cb606dac537492">一个与或表达式解析示例</h3>
<p>了解了flex和bison的功能,我们来看一个示例。这个示例完成了字符串等于或者包含的与或运算。例如可以计算<code>ab == ab && ab ^^ a || ab == a</code>这样子的表达式。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>./expr_parser "ab == ab && ab ^^ a || ab == a"
Expression: (((((ab) == (ab))) && (((ab) ^^ (a)))) || (((ab) == (a))))
Result: 1
</code></pre></div>
<p>关于词法,我们定义了与、或、等于、包含、括号、值这几种,对应着相应的运算。flex源文件的格式如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>%{
#include <string.h>
#include "parser.h"
%}
%%
\n /* ignore end of line */
[ \t]+ /* ignore whitespace */
"&&" return T_AND;
"||" return T_OR;
"==" return T_EQ;
"^^" return T_CT;
"(" return '(';
")" return ')';
[a-zA-Z][a-zA-Z0-9]* yylval.string_literal = strdup(yytext); return T_FIELD;
%%
</code></pre></div>
<p>语法分析把一系列的记号转化为语法分析树,bison的规则基本上就是BNF。bison源文件中BNF规则如下:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>string_filter:
T_FIELD T_EQ T_FIELD
{
$$ = make_op_node(EQ);
$$->left_child = make_left_node($1);
$$->right_child = make_right_node($3);
}
|
T_FIELD T_CT T_FIELD
{
$$ = make_op_node(CT);
$$->left_child = make_left_node($1);
$$->right_child = make_right_node($3);
}
;
</code></pre></div>
<p>从上述代码中可以看出我们将解析后的语法保存在一个树的结构中,打印整个表达式只需要遍历整个树即可。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span><span class="kt">void</span> <span class="nf">print_expression</span><span class="p">(</span><span class="n">node_t</span> <span class="o">*</span><span class="n">root</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">ops</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"&&"</span><span class="p">,</span> <span class="s">"||"</span><span class="p">,</span> <span class="s">"=="</span><span class="p">,</span> <span class="s">"^^"</span><span class="p">};</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">root</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="s">"("</span><span class="p">);</span>
<span class="n">print_expression</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">left_child</span><span class="p">);</span>
<span class="k">switch</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="nl">OP</span><span class="p">:</span>
<span class="n">printf</span><span class="p">(</span><span class="s">" %s "</span><span class="p">,</span> <span class="n">ops</span><span class="p">[</span><span class="n">root</span><span class="o">-></span><span class="n">value</span><span class="p">.</span><span class="n">op</span><span class="p">]);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="nl">LEFT</span><span class="p">:</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"(%s"</span><span class="p">,</span> <span class="n">root</span><span class="o">-></span><span class="n">value</span><span class="p">.</span><span class="n">string_literal</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="nl">RIGHT</span><span class="p">:</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%s)"</span><span class="p">,</span> <span class="n">root</span><span class="o">-></span><span class="n">value</span><span class="p">.</span><span class="n">string_literal</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">default</span><span class="o">:</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">print_expression</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">right_child</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%s"</span><span class="p">,</span> <span class="s">")"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>计算整个表达式的真假,只需要递归就好,很基本的树的操作。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span><span class="kt">int</span> <span class="nf">evaluate_expression</span><span class="p">(</span><span class="n">node_t</span> <span class="o">*</span><span class="n">root</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">root</span><span class="p">)</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="nl">LEFT</span><span class="p">:</span>
<span class="k">case</span> <span class="nl">RIGHT</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">case</span> <span class="nl">OP</span><span class="p">:</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">value</span><span class="p">.</span><span class="n">op</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="nl">EQ</span><span class="p">:</span>
<span class="k">return</span> <span class="n">eval_eq_node</span><span class="p">(</span><span class="n">root</span><span class="p">);</span>
<span class="k">case</span> <span class="nl">CT</span><span class="p">:</span>
<span class="k">return</span> <span class="n">eval_ct_node</span><span class="p">(</span><span class="n">root</span><span class="p">);</span>
<span class="k">case</span> <span class="nl">AND</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span><span class="n">evaluate_expression</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">left_child</span><span class="p">)</span>
<span class="o">&&</span> <span class="n">evaluate_expression</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">right_child</span><span class="p">));</span>
<span class="k">case</span> <span class="nl">OR</span><span class="p">:</span>
<span class="k">return</span> <span class="p">(</span><span class="n">evaluate_expression</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">left_child</span><span class="p">)</span>
<span class="o">||</span> <span class="n">evaluate_expression</span><span class="p">(</span><span class="n">root</span><span class="o">-></span><span class="n">right_child</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>完整的源码在<a href="https://github.com/dieyushi/expr_parser">https://github.com/dieyushi/expr_parser</a></p>
<p>当然该代码离libpcap支持的语法还差的很远,但是该代码稍加改动就可以用于简单的输入输出过滤,如果需要支持新的词法和语法,大家可以自己添加。</p>
DDOS Amplification Attack
2014-02-13T17:50:02+08:00
https://www.zzsec.org/2014/02/ddos-amplification-attack
<p>今天研究了下最近很火的DNS Amplification Attack和NTP Amplification Attack,做了总结。
<a href="https://dl.dropboxusercontent.com/u/79944785/Blog/ddos_amplification_attack.pdf">ddos_amplification_attack</a></p>
UNIX网络编程读书笔记
2014-01-16T12:07:26+08:00
https://www.zzsec.org/2014/01/unix-network-programming
<h3 id="part-654280cbc50">前言</h3>
<p>博客很久没有进行更新了,反思下还是自己太懒了。最近一段时间主要是以学习为主,这几天在读《UNIX网络编程》,加深自己对UNIX编程和网络编程的认识。</p>
<h3 id="accept">Accept</h3>
<p>前一段时间还在找工作的时候,看到过一道笔试题,说的是,accept发生在TCP三次握手的哪个阶段。书上有个图可以很好的解释这个问题。</p>
<!--more-->
<p><img src="https://www.zzsec.org/files/pic/2014-01-16-01.png" alt="TCP"></p>
<h3 id="bind-listen">Bind & Listen</h3>
<p>UNIX网络编程第4章习题中提出了两个问题。</p>
<ol>
<li><strong>如果不调用listen,将会怎么样</strong></li>
<li><strong>如果不调用bind,直接调用listen又会怎么样</strong></li>
</ol>
<p>我们来写程序来测试下会发生什么。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span><span class="cm">/* A Simple Server */</span>
<span class="cp">#include</span> <span class="cpf"><time.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><unistd.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><errno.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><sys/socket.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><netinet/in.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">listenfd</span><span class="p">,</span> <span class="n">connfd</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">servaddr</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="kt">char</span> <span class="n">buff</span><span class="p">[</span><span class="mi">4096</span><span class="p">];</span>
<span class="kt">time_t</span> <span class="n">ticks</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="n">listenfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="o"><</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Error to create socket</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">servaddr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
<span class="n">servaddr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">.</span><span class="n">s_addr</span> <span class="o">=</span> <span class="n">htonl</span><span class="p">(</span><span class="n">INADDR_ANY</span><span class="p">);</span>
<span class="n">servaddr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="mi">9999</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">!=</span> <span class="n">bind</span><span class="p">(</span><span class="n">listenfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">servaddr</span><span class="p">,</span> <span class="p">(</span><span class="kt">socklen_t</span><span class="p">)</span><span class="k">sizeof</span><span class="p">(</span><span class="n">servaddr</span><span class="p">)))</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Error to bind addr</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">!=</span> <span class="n">listen</span><span class="p">(</span><span class="n">listenfd</span><span class="p">,</span> <span class="mi">1024</span><span class="p">))</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Error to listen</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">connfd</span> <span class="o">=</span> <span class="n">accept</span><span class="p">(</span><span class="n">listenfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">connfd</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"errno %d, %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">errno</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">));</span>
<span class="n">ticks</span> <span class="o">=</span> <span class="n">time</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
<span class="n">snprintf</span><span class="p">(</span><span class="n">buff</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buff</span><span class="p">),</span> <span class="s">"%.24s</span><span class="se">\r\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ctime</span><span class="p">(</span><span class="o">&</span><span class="n">ticks</span><span class="p">));</span>
<span class="n">write</span><span class="p">(</span><span class="n">connfd</span><span class="p">,</span> <span class="n">buff</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">buff</span><span class="p">));</span>
<span class="n">close</span><span class="p">(</span><span class="n">connfd</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div><div class="highlight"><pre><code class="language-c" data-lang="c"><span></span><span class="cm">/* A simple Client */</span>
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><unistd.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><errno.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><sys/types.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><sys/socket.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><arpa/inet.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><netinet/in.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">sockfd</span><span class="p">,</span> <span class="n">n</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">recvline</span><span class="p">[</span><span class="mi">4097</span><span class="p">];</span>
<span class="k">struct</span> <span class="n">sockaddr_in</span> <span class="n">servaddr</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
<span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">)</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"usage: %s <IPaddress>"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="n">sockfd</span> <span class="o">=</span> <span class="n">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"socket error</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">servaddr</span><span class="p">.</span><span class="n">sin_family</span> <span class="o">=</span> <span class="n">AF_INET</span><span class="p">;</span>
<span class="n">servaddr</span><span class="p">.</span><span class="n">sin_port</span> <span class="o">=</span> <span class="n">htons</span><span class="p">(</span><span class="mi">9999</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">inet_pton</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">&</span><span class="n">servaddr</span><span class="p">.</span><span class="n">sin_addr</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"inet_pton error for %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">connect</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">servaddr</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">servaddr</span><span class="p">))</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"errno %d, %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">errno</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">));</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"connect error</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">while</span> <span class="p">(</span> <span class="p">(</span><span class="n">n</span> <span class="o">=</span> <span class="n">read</span><span class="p">(</span><span class="n">sockfd</span><span class="p">,</span> <span class="n">recvline</span><span class="p">,</span> <span class="mi">4096</span><span class="p">))</span> <span class="o">></span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">recvline</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">fputs</span><span class="p">(</span><span class="n">recvline</span><span class="p">,</span> <span class="n">stdout</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="n">printf</span><span class="p">(</span><span class="s">"read error</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>分别注释掉Server中的bind和listen,运行后会有下面的结果。</p>
<ul>
<li><p><strong>不调用bind直接调用listen的情况</strong></p>
<ul>
<li>服务器端,listen调用会赋予监听套接字一个临时端口</li>
<li>客户端连接的端口服务器未开放,不在监听状态,connect连接失败,errno为ECONNREFUSED,Connection refused</li>
</ul></li>
<li><p><strong>不调用listen的情况</strong></p>
<ul>
<li>服务器端调用accept失败,返回值-1,errno为EINVAL,Invalid argument</li>
<li>客户端connect调用失败,errno为ETIMEDOUT,Connection timed out</li>
</ul></li>
</ul>
CGI WebServer
2013-10-25T19:52:41+08:00
https://www.zzsec.org/2013/10/cgi-server
<h3 id="part-654280cbc50">前言</h3>
<p>好久没有写博客了,最近一段时间都在忙着确定工作和确定毕业论文题目等事情。好不容易忙完这些事情了,接下来工作方向定了,博客内容就尽量向工作内容靠拢,不会再像之前那样主题天马行空了。</p>
<!--more-->
<h3 id="cgi">CGI简介</h3>
<p>在知道如何写一个 <strong>CGI WebServer</strong> 之前,我们先看下什么是CGI。通用网关接口(Common Gateway Interface),是一种重要的互联网技术,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序,请求数据。CGI描述了客户端和服务器程序之间传输数据的一种标准。</p>
<p>CGI的一个目的是要独立于任何语音额。WebServer无需在这个问题是对语音有任何了解。常见的编写CGI程序的语言有 <em>Perl</em> 、 <em>Unix shell script</em> 、 <em>Python</em> 、 <em>Ruby</em> 、 <em>PHP</em> 、 <em>C/C++</em> 等。</p>
<p>CGI的工作原理,从WEB服务器的角度看,是在特定的位置,如 <strong><a href="http://www.example.com/test.cgi">http://www.example.com/test.cgi</a></strong> 定义了可以运行的CGI程序test.cgi。当收到一个匹配URL的请求,相应的程序就会被调用,并将客户端发送的数据作为输入。程序的输出会由Web服务器手机,并加上合适额HTTP Header,再发送回客户端。</p>
<p>CGI的缺点是每次请求都要生成一个程序的副本来运行,不能承受大的工作量。因此出现了 <strong>FastCGI</strong> ,它会在第一次调用脚本时,缓存脚本编译后的版本。另一种办法是直接把解析器放在Web服务器中,这样就无需新建一个进程来执行脚本, <strong>Apache</strong> 服务器就有很多这样的模块,比如 <em>mod_php</em> 、 <em>mod_python</em> 等等。</p>
<h3 id="part-2bf3829ba130ec65">代码实现</h3>
<p>在<code>GitHub</code>上搜到了一个实现, <strong><a href="https://github.com/klange/cgiserver">https://github.com/klange/cgiserver</a></strong> ,代码很简洁,只有一千多行,但是该有的基本上都有了。它的主要流程是这样子的。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * Accept an incoming connection and pass it on to a new thread.</span>
<span class="cm"> */</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">c_len</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">socket_request</span> <span class="o">*</span> <span class="n">incoming</span> <span class="o">=</span> <span class="n">calloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">socket_request</span><span class="p">),</span><span class="mi">1</span><span class="p">);</span>
<span class="n">c_len</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">incoming</span><span class="o">-></span><span class="n">address</span><span class="p">);</span>
<span class="n">_last_unaccepted</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">incoming</span><span class="p">;</span>
<span class="n">incoming</span><span class="o">-></span><span class="n">fd</span> <span class="o">=</span> <span class="n">accept</span><span class="p">(</span><span class="n">serversock</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="p">(</span><span class="n">incoming</span><span class="o">-></span><span class="n">address</span><span class="p">),</span> <span class="o">&</span><span class="n">c_len</span><span class="p">);</span>
<span class="n">_last_unaccepted</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">pthread_create</span><span class="p">(</span><span class="o">&</span><span class="p">(</span><span class="n">incoming</span><span class="o">-></span><span class="kr">thread</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">handleRequest</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(</span><span class="n">incoming</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div>
<p>对每一个连接都新建一个线程来处理。并且将相关的fd,threadid等信息传给线程。线程中的操作我们只重点看CGI部分,前面Header信息的读取和处理,包括Cookie,Referer,filename等的处理都有很详细的注释,就不详细说明了。</p>
<p>接下来就是经典的Linux管道编程了。fork,pipe,dup2,execl这一系列函数。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="kt">int</span> <span class="n">cgi_pipe_r</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">cgi_pipe_w</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="n">pipe</span><span class="p">(</span><span class="n">cgi_pipe_r</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Failed to create read pipe!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">pipe</span><span class="p">(</span><span class="n">cgi_pipe_w</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Failed to create write pipe!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/*</span>
<span class="cm"> * Fork.</span>
<span class="cm"> */</span>
<span class="kt">pid_t</span> <span class="n">_pid</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">_pid</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span>
</code></pre></div>
<p>先准备管道,然后fork出来子进程。将子进程的标准输出重定向到管道1,将子进程的标准输入重定向到管道0,这样子就能在父进程中处理子进程的输入输出了。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="n">dup2</span><span class="p">(</span><span class="n">cgi_pipe_r</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">STDIN_FILENO</span><span class="p">);</span>
<span class="n">dup2</span><span class="p">(</span><span class="n">cgi_pipe_w</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="n">STDOUT_FILENO</span><span class="p">);</span>
</code></pre></div>
<p>之后就是进入目录,使用<code>setenv</code>来设置环境变量。最重要的是设置 <strong>SCRIPT_NAME</strong> , <strong>SCRIPT_FILENAME</strong> 这些。之后就是执行脚本了。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="kt">char</span> <span class="n">executable</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
<span class="n">executable</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
<span class="n">sprintf</span><span class="p">(</span><span class="n">executable</span><span class="p">,</span> <span class="s">"./%s"</span><span class="p">,</span> <span class="n">_filename</span><span class="p">);</span>
<span class="n">execlp</span><span class="p">(</span><span class="n">executable</span><span class="p">,</span> <span class="n">executable</span><span class="p">,(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mi">0</span><span class="p">);</span>
</code></pre></div>
<p>执行脚本前首先要将请求的数据当作输入写到管道中。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="k">while</span> <span class="p">((</span><span class="n">total_read</span> <span class="o"><</span> <span class="n">c_length</span><span class="p">)</span> <span class="o">&&</span> <span class="p">(</span><span class="o">!</span><span class="n">feof</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">)))</span> <span class="p">{</span>
<span class="kt">size_t</span> <span class="n">diff</span> <span class="o">=</span> <span class="n">c_length</span> <span class="o">-</span> <span class="n">total_read</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">diff</span> <span class="o">></span> <span class="n">CGI_POST</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * If there's more than our buffer left,</span>
<span class="cm"> * obviously, only read enough for the buffer.</span>
<span class="cm"> */</span>
<span class="n">diff</span> <span class="o">=</span> <span class="n">CGI_POST</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">size_t</span> <span class="n">read</span><span class="p">;</span>
<span class="n">read</span> <span class="o">=</span> <span class="n">fread</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">diff</span><span class="p">,</span> <span class="n">socket_stream</span><span class="p">);</span>
<span class="n">total_read</span> <span class="o">+=</span> <span class="n">read</span><span class="p">;</span>
<span class="cm">/*</span>
<span class="cm"> * Write to the CGI pipe</span>
<span class="cm"> */</span>
<span class="n">fwrite</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">read</span><span class="p">,</span> <span class="n">cgi_pipe_post</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>接下来就是从cgi_pipe中读取信息,首先了是读取头信息。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="n">fprintf</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">,</span> <span class="s">"HTTP/1.1 200 OK</span><span class="se">\r\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">,</span> <span class="s">"Server: "</span> <span class="n">VERSION_STRING</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">);</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">feof</span><span class="p">(</span><span class="n">cgi_pipe</span><span class="p">))</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * Read until we are out of headers.</span>
<span class="cm"> */</span>
<span class="kt">char</span> <span class="o">*</span> <span class="n">in</span> <span class="o">=</span> <span class="n">fgets</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="n">CGI_BUFFER</span> <span class="o">-</span> <span class="mi">2</span><span class="p">,</span> <span class="n">cgi_pipe</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">in</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="s">"[warn] Read nothing [%d on %p %d %d]</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">ferror</span><span class="p">(</span><span class="n">cgi_pipe</span><span class="p">),</span> <span class="n">cgi_pipe</span><span class="p">,</span> <span class="n">cgi_pipe_w</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">_pid</span><span class="p">);</span>
<span class="n">perror</span><span class="p">(</span><span class="s">"[warn] Specifically"</span><span class="p">);</span>
<span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">strcmp</span><span class="p">(</span><span class="n">in</span><span class="p">,</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span><span class="n">strcmp</span><span class="p">(</span><span class="n">in</span><span class="p">,</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">))</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * Done reading headers.</span>
<span class="cm"> */</span>
<span class="n">buf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">strstr</span><span class="p">(</span><span class="n">in</span><span class="p">,</span> <span class="s">": "</span><span class="p">)</span> <span class="o">&&</span> <span class="o">!</span><span class="n">strstr</span><span class="p">(</span><span class="n">in</span><span class="p">,</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">))</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * Line was too long or is garbage?</span>
<span class="cm"> */</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"[warn] Garbage trying to read header line from CGI [%zu]</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">buf</span><span class="p">));</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">fwrite</span><span class="p">(</span><span class="n">in</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">in</span><span class="p">),</span> <span class="n">socket_stream</span><span class="p">);</span>
<span class="c1">//fprintf(socket_stream, "%s", buf);</span>
<span class="o">++</span><span class="n">j</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>遇到<code>\r\n</code>说明读到Header结束后,接着就是读取CGI的返回信息。</p>
<div class="highlight"><pre><code class="language-c" data-lang="c"><span></span> <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">feof</span><span class="p">(</span><span class="n">cgi_pipe</span><span class="p">))</span> <span class="p">{</span>
<span class="kt">size_t</span> <span class="n">read</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="n">read</span> <span class="o">=</span> <span class="n">fread</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">CGI_BUFFER</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">cgi_pipe</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">read</span> <span class="o"><</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * Read nothing, we are done (or something broke)</span>
<span class="cm"> */</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"[warn] Read nothing on content without eof.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">perror</span><span class="p">(</span><span class="s">"[warn] Error on read"</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">enc_mode</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/*</span>
<span class="cm"> * Length of this chunk.</span>
<span class="cm"> */</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">,</span> <span class="s">"</span><span class="se">\r\n</span><span class="s">%zX</span><span class="se">\r\n</span><span class="s">"</span><span class="p">,</span> <span class="n">read</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">fwrite</span><span class="p">(</span><span class="n">buf</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">read</span><span class="p">,</span> <span class="n">socket_stream</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>将这些信息发送到了客户端之后就是一些资源释放的操作了。</p>
<p>很简单吧,这样子就可以实现一个CGI WebServer了。</p>
sse4.2带来的优化
2013-08-16T20:25:53+08:00
https://www.zzsec.org/2013/08/using-sse_4.2
<h3 id="part-654280cbc50">前言</h3>
<p>最近这一周做的事情是想办法让字符串处理的相关函数变的更快,为了应对大数据量的字符串处理。经过一段时间的努力,还算有点效果,可以比使用标准库要快的多。整个过程主要用到的是Intel的<code>SSE 4.2</code>中字符处理的相关指令,<code>PCMPISTRI</code>和<code>PCMPISTRM</code>,下面稍微总结下。</p>
<!--more-->
<h3 id="aggregation-operations">Aggregation operations</h3>
<p>这是这个指令比较核心的内容,通过imm[3:2]来设置。</p>
<p><strong>Equal Each</strong>, imm[3:2] = 10b, 比较两个字符串,例子如下</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>operand1 = "UseFlatAssembler"
operand2 = "UsingAnAssembler"
IntRes1 = 1100000111111111
</code></pre></div>
<p><strong>Equal Any</strong>, imm[3:2] = 00b, 直接看例子吧。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>operand2 = "You Drive Me Mad"
operand1 = "aeiouy"
IntRes1 = 0110001010010010
</code></pre></div>
<p><strong>Ranges</strong>, imm[3:2] = 01b, 判断一个字符是否子啊某一个范围。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>operand2 = "I'm here because"
operand1 = "azAZ"
IntRes1 = 1010111101111111
</code></pre></div>
<p><strong>Equal Ordered</strong>, imm[3:2] = 11b, 判断是否是字串。</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>operand2 = "WhenWeWillBeWed!"
operand1 = "We"
IntRes1 = 000010000000100
</code></pre></div>
<p>结果会写到ECX或者xmm0, 同时会影响CF,ZF等一些标志位,具体的可以看参考中intel的手册。</p>
<h3 id="part-2d2feb2ad4e008eb">注意事项</h3>
<ul>
<li>使用这个指令时字符串不需要对齐</li>
<li>CPU会处理'\0'字符的</li>
<li>可以使用这条指令来处理宽字符</li>
<li>PCMPISTRI返回的是index,PCMPISTRM返回的是mask</li>
</ul>
<h3 id="part-65429d8401b">总结</h3>
<p>这两条指令可以用来实现strlen,strchr,strstr,strcmp等一些函数,glibc也的确用到了这些指令,但是它在实现是考虑的事项太多了,对于我们架构已经固定的应用,可以做很多很多针对性的优化的。代码就不贴了。。</p>
<h3 id="part-65428734206">参考</h3>
<ul>
<li><a href="http://www.strchr.com/strcmp_and_strlen_using_sse_4.2">http://www.strchr.com/strcmp_and_strlen_using_sse_4.2</a></li>
<li><a href="http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2b-manual.pdf">http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2b-manual.pdf</a></li>
</ul>
Linux内核态与用户态通信的常用方法
2013-08-05T20:33:53+08:00
https://www.zzsec.org/2013/08/communication-between-linux-kernel-and-user-space-program
<h3 id="part-654280cbc50">前言</h3>
<p>最近做的事情很多地方用到Linux驱动层与应用层的通信,在此总结下常见的并且在我工作中用到的通信方法。</p>
<h3 id="part-65429d8401b">总结</h3>
<p>由于每种方法都可以找到大量的示例代码,同时还有详细的函数手册,我就不贴代码了。只列下相关的方法和一个链接。</p>
<ul>
<li><a href="http://oss.org.cn/kernel-book/ldd3/ch04s03.html#UsingtheprocFilesystem">procfs</a></li>
<li><a href="http://linux.die.net/man/7/netlink">netlink</a></li>
<li>syscall</li>
</ul>
<p>syscall的范围就广了,通过注册字符设备可以使用mmap和ioctl等来进行操作,要注意的是在内核态ioctl已经被废弃,现在应该使用unlocked_ioctl,需要自己来加锁。</p>
<p>用户态通过系统暴露出来的系统调用来进行操作,如mmap,ioctl,open,close,read,write,内核态通过建立共享内存remap_pfn_range或者copy_to_user, copy_from_user来进行操作。</p>
<p>选择哪种方式需要考虑是用户态单进程与内核态通信还是多进程的通信,还要考虑通信的数据量。根据不同的需求来使用不同的方法。</p>
最近的一些事情
2013-08-03T21:38:46+08:00
https://www.zzsec.org/2013/08/something-recently
<h3 id="part-654280cbc50">前言</h3>
<p>好久没写博客了,这一段时间是疯狂的学习加上每周末一群小伙伴们出去晒太阳,就这样不知不觉已经一个月了。今天难得偷会闲并且有心情,写篇博客记录下这一段时间做的事情。不管怎么说,来到这里实习完全是意料外的事情,最后入职的岗位和具体工作也是我一直想做的内容,也见到了传说中的各位大牛,以后回想起这段努力工作的日子,应该会很幸福的。</p>
<h3 id="part-6542aa5d53a">学习</h3>
<p>总体来说,现在做的事情和在学习做的事情是完全两码事,刚上手的时候的确很忧心忡忡,对着文档想如果这就是需求让我来实现该怎么做,结果是各种不知道。这段时间恶补了相关知识。我这段时间工作相关的一些知识如下:</p>
<!--more-->
<ul>
<li>TCP/IP协议的深入理解</li>
<li>linux设备驱动的相关知识</li>
<li>linux C代码优化</li>
</ul>
<p>我之前对有些东西懵懵懂懂的,现在这一段时间深入了解了相关内容。不过我学到的最重要的东西是如何写出高质量的C代码,如何优化代码,如何精简代码,怎样定义合适的数据结构和算法。以前在实验室是结果导向,东西跑起来就一起OK,现在学到的更多的是如何保证稳定高效的运行。</p>
<p>我师兄review我的代码时提的建议真的让我受益匪浅啊。在此表示膜拜和感谢。</p>
<h3 id="part-3786c0c8fa42a93">吃喝玩</h3>
<p>一句话总结,很精致,但不适合我这种大汉啊。。最后上图吧。</p>
<p><img src="http://distilleryimage11.ak.instagram.com/1c0804e4e6dc11e2adbf22000aaa04d4_7.jpg" alt=""></p>
<p><img src="http://distilleryimage8.ak.instagram.com/e39b76aaec8911e2926322000aaa0aa5_7.jpg" alt=""></p>
博客暂时停更
2013-07-10T18:27:05+08:00
https://www.zzsec.org/2013/07/blog-suspend
<p>闭关修炼中,博客暂时停更。</p>
插件实现XSS检测
2013-06-22T11:04:11+08:00
https://www.zzsec.org/2013/06/xss-detection-in-chrome
<h3 id="part-654280cbc50">前言</h3>
<p>有很多软件可以做XSS的检测,如<a href="http://xsser.sourceforge.net/">XSSer</a>等等。本文实现的着重点不是XSS的检测,而是XSS触发之后的行为检测,呃,直接点说就是拦截发送Cookie这一行为。</p>
<h3 id="part-6542ab391fb">实现</h3>
<p>通过使用<code>chrome.* APIs</code>,我们可以实现请求拦截,cookie获取等行为。具体实现如下:</p>
<!--more-->
<div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span></span><span class="nx">chrome</span><span class="p">.</span><span class="nx">webRequest</span><span class="p">.</span><span class="nx">onBeforeRequest</span><span class="p">.</span><span class="nx">addListener</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span> <span class="nx">details</span> <span class="p">)</span> <span class="p">{</span>
<span class="nx">chrome</span><span class="p">.</span><span class="nx">tabs</span><span class="p">.</span><span class="nx">query</span><span class="p">({</span><span class="s1">'active'</span><span class="o">:</span> <span class="kc">true</span><span class="p">},</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">tabs</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">url</span> <span class="o">=</span> <span class="nx">tabs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">url</span><span class="p">;</span>
<span class="nx">CookieString</span> <span class="o">=</span> <span class="s2">""</span><span class="p">;</span>
<span class="nx">chrome</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">getAll</span><span class="p">({</span><span class="nx">url</span><span class="o">:</span> <span class="nx">url</span><span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">cookies</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">cookies</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">cookies</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">httpOnly</span> <span class="o">==</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">CookieString</span> <span class="o">+=</span> <span class="nx">cookies</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">"="</span> <span class="o">+</span> <span class="nx">cookies</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">value</span> <span class="o">+</span> <span class="s2">"; "</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">CookieString</span> <span class="o">+=</span> <span class="nx">cookies</span><span class="p">[</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">length</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nx">name</span> <span class="o">+</span> <span class="s2">"="</span> <span class="o">+</span> <span class="nx">cookies</span><span class="p">[</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">length</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="nx">value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">details</span><span class="p">.</span><span class="nx">url</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">escape</span><span class="p">(</span><span class="nx">CookieString</span><span class="p">))</span> <span class="o">></span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">details</span><span class="p">.</span><span class="nx">url</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">CookieString</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span><span class="p">){</span>
<span class="nx">chrome</span><span class="p">.</span><span class="nx">tabs</span><span class="p">.</span><span class="nx">query</span><span class="p">({</span><span class="s1">'active'</span><span class="o">:</span> <span class="kc">true</span><span class="p">},</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">tabs</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">chrome</span><span class="p">.</span><span class="nx">tabs</span><span class="p">.</span><span class="nx">remove</span><span class="p">(</span><span class="nx">tabs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">id</span><span class="p">,</span> <span class="kd">function</span><span class="p">(){});</span>
<span class="p">});</span>
<span class="nx">alert</span><span class="p">(</span><span class="s2">"cookies stealen"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="p">},</span>
<span class="p">{</span><span class="nx">urls</span><span class="o">:</span> <span class="p">[</span><span class="s2">"<all_urls>"</span><span class="p">]},</span>
<span class="p">[</span><span class="s2">"blocking"</span><span class="p">]</span>
<span class="p">);</span>
</code></pre></div>
<p>其实上面的代码只是关闭了标签页,不过由于是异步调用,cookie在关闭之前早就发出去了。怎么block这个webrequest呢。</p>
<h3 id="part-65428734206">参考</h3>
<ol>
<li><a href="https://developer.chrome.com/extensions/getstarted.html">https://developer.chrome.com/extensions/getstarted.html</a></li>
<li><a href="https://developer.chrome.com/extensions/cookies.html">https://developer.chrome.com/extensions/cookies.html</a></li>
<li><a href="https://developer.chrome.com/extensions/tabs.html">https://developer.chrome.com/extensions/tabs.html</a></li>
</ol>
sqlmap的一些小技巧
2013-06-13T22:28:58+08:00
https://www.zzsec.org/2013/06/some-skills-about-sqlmap
<h3 id="part-654280cbc50">前言</h3>
<p>很多人都使用sqlmap来进行SQL注入测试,但是很多人只是简简单单的<code>current-user</code>,<code>current-db</code>,<code>-D</code>,<code>-T</code>,<code>--dump</code>这样子来做,其实sqlmap还有很多很强大的功能,这里简单的总结下。</p>
<h4 id="post">POST注入</h4>
<p>有两种方法来进行post注入,一种是使用<code>--data</code>参数,将post的key和value用类似GET方式来提交。二是使用<code>-r</code>参数,sqlmap读取用户抓到的POST请求包,来进行POST注入检测。</p>
<h4 id="payload">查看payload</h4>
<p>之前一直是加本地代理,然后用burpsuit来看sqlmap的payload,到现在才发现用<code>-v</code>参数就可以实现。一直认为<code>-v</code>实现的只是控制警告,debug信息级别。实际上使用<code>-v 3</code>就可以显示注入的payload,4,5,6还可以显示HTTP请求,HTTP响应头和页面。</p>
<!--more-->
<h4 id="google">使用google搜索</h4>
<p>sqlmap可以测试google搜索结果中的sql注入,很强大的功能吧。使用方法是参数<code>-g</code>。不过感觉实际使用中这个用的还是很少的。</p>
<h4 id="part-2e83c1c3ff4e8cb5">请求延时</h4>
<p>在注入过程中请求太频繁的话可能会被防火墙拦截,这时候<code>--delay</code>参数就起作用了。可以设定两次HTTP请求间的延时。有的web程序会在多次错误访问后屏蔽所有请求,这样就导致之后所有的测试无法进行,绕过这个策略可以使用<code>--safe-url</code>,每隔一段时间去访问一个正常的页面。</p>
<h4 id="part-71e9b564bcd0a3fc">伪静态页面</h4>
<p>有些web服务器进行了url rewrite或者网站是伪静态的,无法直接提供测试参数,这样子可以使用<code>*</code>来代替要测试的参数。</p>
<h4 id="part-462661e777b1837c">执行系统命令</h4>
<p>当数据库支持,并且当前用户有权限的时候,可以执行系统命令,使用<code>--os-cmd</code>或者<code>--os-shell</code>,具体的讲,当可以执行多语句的时候,会尝试用UDF(MySQL,PostgrepSQL)或者xp_cmdshell(MSSQL)来执行系统命令。不能执行多语句时,仍然会尝试创建一个webshell来执行语句,这时候就需要web的绝对路径了。总体来说,成功率偏低,不过个人也有成功的经验~</p>
<h4 id="part-2d360934d65f303c">测试等级</h4>
<p>sqlmap使用<code>--level</code>参数来进行不同全面性的测试,默认为1,不同的参数影响了使用哪些payload,2时会进行cookie注入检测,3时会进行<code>useragent</code>检测。</p>
<h3 id="part-65428734206">参考</h3>
<ul>
<li><a href="https://github.com/sqlmapproject/sqlmap/wiki/Usage">https://github.com/sqlmapproject/sqlmap/wiki/Usage</a></li>
</ul>