如何调试iptables [CentOS 7]

首先,来一张非常有用的图:

基础知识

iptables可以jump到TRACE目标,开启_包追踪_(packet tracing)选项。 iptables有一个raw表,基本上是iptables最先处理包的地方。

 开始调试

在最入口的位置给符合条件的包开启包追踪,比如对所有进入的icmp包:

1
iptables -t raw -I PREROUTING -p icmp -j TRACE

有的时候,还需要加载需要的模块(CentOS 7下):

1
modprobe nf_log_ipv4

然后你就可以在/var/log/messages日志中看到包追踪信息了。

阅读更多

[译]输入系统如何工作——键盘输入

本文是 How input works – Keyboard input 的翻译。

上一篇博客中,原作者解释了KWin中,输入设备是如何打开和处理的。在这篇博文中,我们将仔细关注下键盘设备和键盘事件。

键盘并不总是键盘

在Linux中,键盘是一个非常奇特的设备。你不会只有一个键盘,你肯定会有很多个。很多设备宣称自己是键盘,但是只支持一个键。比如,电源按钮或者带静音按钮、音量加减按钮的外置耳机。从输入系统的角度来看,这些设备也是键盘。

对于KWin,发现真正支持的键盘是很重要的。如果没有一个“真的”键盘连接(或者说开启),我们的虚拟键盘应该自动激活。比如,如果你从平板PC二合一设备上拔了键盘,它应该转换为平板模式,即有虚拟键盘的模式。如果连接上了键盘,虚拟键盘就不是主要的输入设备了。libinput提供了函数来检测键盘支持哪些键。我们使用这个功能来区分不同的键盘类型。

键盘事件

在这里,键盘是最简单的输入设备。libinput仅仅触发一个LIBINPUT_EVENT_KEYBOARD_KEY事件,并包含了被按下或者释放的键。KWin有一个专用线程,用来从libinput读取事件。所以这些事件现在仅仅是放在处理队列中,主线程同时也得到新事件通知。一旦主线程处理事件,事件就被转换成我们的输入重定向类。不管事件是通过哪种源头抵达,所有输入事件都会通过输入重定向。KWin不仅仅支持来自libinput的事件,并且支持嵌套会话(即KWin运行在X11之上,或者在另一个Wayland服务器之上),还有在集成测试中使用的模拟事件。这意味着一旦事件到达输入重定向,我们基本上就丢失了事件来自哪个设备这些信息。最近,我们扩展了内部API,可以在事件处理函数中包含设备源,这是可选的。可以在调试终端中使用,来显示哪些设备产生了哪些事件。

xkbcommon

现在,一个键的按下、释放事件到达了中心分发方法KeyboardInputRedirection::processKey。第一件也是重要的一件事就是在xbkcommon中更新键盘状态。xkbcommon被用将物理键为事件,转换过程根据键盘布局、键盘状态(比如激活的修饰符)来进行。比如:如果我按下了“y”键(键码是21)并且“Shift”键是按下的状态,在德语键盘布局下,就会创建“Z”按下的事件;但是在英语键盘布局下,它会是“Y”。

在KWin中,我们将所有需要的xkbcommon功能都封装到Xkb类中。这个类追踪活跃的键盘布局、执行键盘布局切换(当布局变换的时候展示OSD)。它知道上一次按键的符号,当前活跃的修饰符和快捷键相关的修饰符。

阅读更多

[译]输入系统如何工作——创建设备

本文是How input works – creating a Device的翻译。

最近,我(原作者,下同)在KWin/Wayland输入栈上做了一些工作,比如实现了鼠标手势和鼠标限制协议(pointer constraints protocol),并且想写一些系列博客来描述输入事件是如何从设备传递到应用的。在第一篇博文中,我将关注于创建和配置输入设备,以及与此相关的其他事情。

evdev

Linux内核通过evdev API来产生输入事件。如果你对evdev如何工作感兴趣,我推荐你读一读Peter Hutterer写的优秀的博文。对于我们关注的层面来说,输入事件API太底层了,我们仅仅想用对它的一个抽象。

libinput 和设备文件

对输入事件API的抽象叫做libinput。它允许我们得到通知,不论何时添加、删除输入设备、不论何时产生输入事件。但是别急,我们首先需要打开输入设备,这是我们的第一个挑战。

正常情况下,设备文件不能被用户读取。这有好的一面,否则每个程序都能够读取所有的键盘事件。这种情况下,键盘记录器太容易实现了。

但是如果KWin以普通用户的方式运行,普通用户又无法读取设备文件,那KWin如何获取输入?为了让KWin获取输入,我们需要特殊的支持。libinput就是为这种情况准备的,它自己不会尝试打开文件,它会使用用户提供的open_restricted函数。KWin就是这么干的,并将打开文件的任务交给了logind。logind允许一个进程控制当前登录会话。并且这个登录会话的控制进程可以打开一些设备文件。所以KWin和logind的dbus API交互,成为登录会话的控制进程,通过logind的API打开设备文件,并将其传递回libinput。

这也是为什么对于整个Wayland会话,KWin在运行时依赖logind的DBus接口。请注意,这并不意味着你需要使用logind或者sysemd。这仅仅意味着需要一个进程来同logind的DBus接口通讯。

KWin中的设备

阅读更多

strace 速查表

此文是 strace cheat sheet 的翻译。

TL;DR

strace 可以追踪系统调用、信号,在调试中,它还是收集上下文环境的非常好的工具。 此速查表将会展示一些技巧来说明 strace 的使用方法、如何过滤输出,并且介绍了一些 strace 的实用参数。

strace PTRACE_TRACEME EPERM (Operation not permitted)

你应该以 root 身份来运行 strace。如果你以 root 用户运行,也得到这个提示,这说明在你的系统中,strace 不允许附加到进程上。 你可以修改 /proc 中的设置,来开启 strace 附加到进程的功能:

1
sudo bash -c 'echo 0 > /proc/sys/kernel/yama/ptrace_scope'

为了让这个修改永久生效,请首先检查你的系统有没有 /etc/sysctl.d/10-ptrace.conf  文件。 如果你的系统有这个文件,修改该文件:

1
kernel.yama.ptrace_scope = 0

如果你的系统没有这个文件:

  1. 打开 /etc/sysctl.conf 文件
  2. 找到设置 kernel.yama.ptrace_scope
  3. 如果该设置存在,将其修改为 0
  4. 如果不存在,添加一行 kernel.yama.ptrace_scope = 0
阅读更多

unzip的中文问题

唉,unzip的-O选项一直是一个传说中的存在,而且unzip的开发者一直没有意向修复。 故自己动手,丰衣足食,用python写了一个MultiCharset ZIP,代码附上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import zipfile
from optparse import OptionParser

def listZip(zipf):
    print "Archive:  %s" %zipf
    print "  Length      Date    Time    Name"
    print "---------  ---------- -----   ----"
    filist=zipfile.ZipFile(zipf).infolist()
    totalnum=0
    totalsize=0
    for finfo in filist:
        totalnum+=1
        totalsize+=finfo.file_size
        print "%9d " %finfo.file_size ,
        print "%04d-%02d-%02d" %(finfo.date_time[0],finfo.date_time[1],finfo.date_time[2]),
        print "%02d:%02d  " %(finfo.date_time[3],finfo.date_time[4]),
        print finfo.filename.decode('gb18030').encode('utf-8')
    print "---------                     -------"
    print "%9d" %totalsize ,
    print "                   ",
    print "%d files" %totalnum

def exZip(zipf,exdir):
    zf=zipfile.ZipFile(zipf)
    nlist=zf.namelist()
    nlist.sort(key=lambda x:len(x))
    for fn in nlist:
        fnew=unicode(fn,'gb2312').encode('utf8')
        if fnew.endswith('/'):
            os.mkdir(exdir+fnew)
        else:
            file(exdir+fnew,'wb').write(zf.read(fn))
        print fnew
    zf.close()

def main():
    usage = "usage: "+sys.argv[0]+" [options] zipfile1 zipfile2"
    parser = OptionParser(usage=usage)
    parser.add_option("-l","--list",action="store_true",help="list files in zip file",dest="islist",default=True)
    parser.add_option("-x","--extract",action="store_true",help="extract zip files",dest="isex",default=False)
    parser.add_option("-d","--exdir",action="store",help="define extract directory",dest="exdir",default=".")
    #parser.add_option("-z","--exdir",action="store",dest="exidr")

    (options,args)=parser.parse_args();

    if(options.isex):
        for zf in args:
            exZip(zf,options.exdir+"/")
    else:
        if(options.islist):
            for zf in args:
                listZip(zf)

if __name__ == "__main__":
    main()

可以在~/bin/目录下创建一个mczip文件,写入代码,添加可执行权限,即可在终端中用mczip来列出zip文件内容、解压zip文件。

用法:

1
2
3
4
5
6
Usage:mczip.py [options] zipfile1 zipfile2
Options:
-h, --help            show this help message and exit
-l, --list            list files in zip file
-x, --extract         extract zip files
-d EXDIR, --exdir=EXDIR     define extract directory`

只有列出zip包的文件内容和解压zip文件两个功能,只能处理gb18030编码。

注:Python3的zip模块判断更加奇葩了,只要文件名不是ascii编码,就认为是utf8编码,而且不保留bytes格式的文件名,有点难办啊。

阅读更多