monitor the interface other than 802.3

从前只用 wireshark 监听过有线以太网,这次尝试一下其它接口。

问题描述

监听有线以太网比较简单,不需要特殊的设置,只要启动 wireshark 就可以自动把网卡设置在混杂模式下,可以监听到网线上的一切信息。但对于 wifi 就不一样了,一般情况下监听到只是用户数据,连以太网头部都是伪造的。

使用 aircrack

首先需要下载 aircrack,编译安装不在话下。之后的过程就比较简单了。

# ifconfig wlan0 down
# airmon-ng start wlan0

此时会多了一个 mon0 网络接口,启动 wireshark 监听这个接口就可以看到 802.11 协议的内容了。

如果能监听到握手数据包,再配合密码本,就可以使用 aircrack 来破解网络密码了,这个可以使用 aircrack 自带的示例报文 wpa.cap 来测试,如果要实际运用可能需要一个比较好的密码本。

恢复 wifi 功能

如果要恢复 wifi 上网,还需要执行下面的命令

# ifconfig mon0 down
# airmon-ng stop wlan0
# ifconfig wlan0 up

监听 USB 接口

USB 接口的监听(sniffer or monitor)在 Linux 操作系统中有很好的支持,只要加载 usbmon 模块(在 Driver/USB 下面)就可以了,不过需要内核支持 DEBUG_FS(CONFIG_DEBUG_FS 在 Kernel Hacking/Compiler options/Debug Filesystem 下面,这个太容易让人误解为对文件系统的调试了)。关于 usbmon 在内核文档中有详细的说明,我们只需要执行下面两步,就可以通过 wireshark 监听了。

# mount -t debugfs none_debugs /sys/kernel/debug
# modprobe usbmon

通过 lsusb 命令可以知道要监听的设备在哪条 USB 总线上,然后在 wireshark 中的接口列表中选择相应的总线即可。

使用 wireshark 监听到的并不是真正在 USB 总线上传输的电信号,而是从操作系统角度看到的 USB 的协议交互过程。比如可以看到读取描述符,读取配置信息,和对 USB 的配置进行设置等。最重要的是可以看到主机与 USB 的各个端点的通信过程,这对协议分析是最重要的。

需要注意的是,有时候可以看到 0 字节的 BULK IN 请求,这应该是主机软件提出了异步的输入请求,这样就可以同时进行两个方向的传输,提高 USB 总线的效率。

Install EmDebian to DIM3517

在闲置的 DIM3517 开发板上安装 Debian

开发板简介

DIM3517 是 SEED 公司推出的 AM3517 开发板,闲置很长时间了,今天准备拿它玩玩……

主机准备

由于使用了 multistrap 工具,所以主机上必须安装:

$ sudo apt-get install multistrap dpkg-dev

之后需要准备 multistrap 的配置文件,目前我的配置文件是这样的:

[General]
noauth=true
unpack=true
debootstrap=Grip
aptsources=Grip
[Grip]
# space separated package list
packages=netbase ifupdown iproute net-tools apt
source=http://www.emdebian.org/grip
suite=wheezy-grip

由于我参考的网页并没有 packages 那一行,结果生成的文件系统没有网络配置工具,也没有 apt 工具,造成接下来的安装非常麻烦,必须手工使用 dpkg 安装缺少的包。如果采用上面的设置就应该没有问题了。

接下来运行:

$ multistrap -a armel -d $PWD/debian -f multistrap.conf

就可以从网上下载并在 debian 目录下生成初始的文件系统了。

运行 Debian 系统

上面的过程仅仅是把安装文件展开,所有的包都还没有配置。为了完成配置过程,我把生成的文件系统复制到了 SD 卡上,然后重新启动开发板,希望可以登录到新的文件系统上。由于系统并没有配置,所以要在启动参数上加上 init=/bin/sh。可结果还是启动失败,系统显示:

warning: unable to open initial console

这是一个比较熟悉的问题,原因是 /dev/ 目录下没有 console 文件,建立好这个文件之后系统就可以正常启动了,之后需要运行:

# mount -t proc nodev /proc
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin  dpkg --configure -a

可是这个过程也不顺利,dash 和 bash 都没有成功配置,通过网络搜索,找到了解决办法,需要先执行下面的命令:

# /var/lib/dpkg/info/dash.preinst install

终于都配置好了。但在重启系统之前还要再修改几个系统配置文件,这个过程是在另外一台电脑上直接修改 SD 卡上的文件的方法实现的。需要修改的文件如下:

  1. inittab 文件,增加在串口终端上的登录功能,即增加如下内容:
T0:23:respawn:/sbin/getty -L ttyS2 115200 vt100
  1. 去掉 root 用户的密码

再次启动的时候仍然失败,错误消息类似如下:

udevd[45]: unable to receive ctrl connection: Function not implemented

这个问题明显是 udevd 造成,网上没有特别好的解决办法,好像要升级系统的内核,但鉴于我现在升级内核比较困难,我直接删除了 udevd 文件,这样就可以启动系统了,只是没有了自动生成设备文件的功能。

接下来的配置过程就比较简单了。只要安装好了 apt-get,一切就和一个普通的 Debian 系统没有什么区别,只要 apt-get install 就可以把一切搞定。

Install Qt5.2.0 to Mac

在 Macbook Air 上安装 Qt5.2.0

从前 MBA 上安装的是 Qt4.7.4,今天下载了 5.2.0 版本,结果安装的过程竟然出了一些问题。

首先是安装过程出错,出错信息是

Command install_name_tool failed

一共出现两次,分别对应于一个 QtQuickMultimedia 和一个 QtBluetooth 的库,考虑到这两个部分可能不会用到,我选择了 Ignore 继续安装。

安装之后看起来都正常,结果 qmake 竟然也失败,说找不到 macx-clang 配置文件。使用

$ qmake -query

查询一下,发现 Qt 所默认的路径都是 /usr/local,和安装的路径选择不一致。于是在 /usr/local 下面建立了一个对于我安装目录的符号链接,具体的链接为

Qt-5.2.0 -> /Users/myuser/Qt5.2.0/5.2.0/clang_64/

Hands on mbed LPC1768

ARM 公司赠送的 mbed 开发板放在我的桌子上已经很长时间了,今天准备试试看

下载第一个程序

打开开发板的包装就可以看到一个只有 DIP40 大小的开发板,板上有一个 MiniUSB 的插头,显然这就是它的编程接口。可当我将开发板接上 USB 电缆,系统识别出来的竟然是一个 USB 存储器,这倒是一个不小的意外。通过打开存储器里面的 MBED.HTM 文件,就可以登录到 mbed 项目的官方网站,注册一个用户就可以使用在线工具编程开发了。

简单来说,使用 mbed 开发主要有三个步骤:

  1. 通过 USB 电缆连接开发板
  2. 使用在线开发环境进行编程,并最终生成二进制文件
  3. 将二进制文件放到 USB 存储器,按下板上复位按钮运行

mbed 的优点

mbed 的这种开发方式还是很新颖的,只用了几分钟的时间我就已经把第一个程序运行起来了。而作为用户,不用了解 ARM 芯片的任何知识,也不用了解编译器的相关概念,甚至在自己电脑上都不用安装任何新软件。所有的开发都可以通过浏览器完成,所有硬件的细节都被抽象成了用户 API,非常适合刚刚接触嵌入式的人士使用。

个人认为 mbed 比较适合高中生或者业余非专业人员使用,而对于专业嵌入式开发者可能会觉得它隐藏了太多的细节,更像一个玩具而不是一个开发工具。或者换句话说,专业人士如果使用 mbed,有一天碰见了一个高中生,那个高中生说:“我用的也是这个”,这或多或少会让专业人士少了些神秘感,甚至感觉有点“丢份”。就像一个 Linux Hack,要么只用 terminal,要么就使用一个平铺的窗口管理器,总之必须满屏幕是字符才会让他觉得有真正黑客的自尊。

不过 mbed 还是非常适合快速开发的。如果有一个项目工期很紧,使用 mbed 也不失好的选择。

离线开发

在线开发方式也不讨好专业人士,好在网站提供了离线的开发方法。在项目的右击菜单中有 Export Program 的选项,可以导出为 Keil,DS-5,GCC,IAR 等多种开发平台的工程,其中也包含 mbed 的链接库。因此即使使用离线开发工具,依然也可以使用 mbed 提供的 API,方便用户的开发。

离线的方式使用户可以继续使用熟悉的开发工具,而且同样可以把生成的二进制映像拷贝到 mbed 的存储器中,“自动”下载程序到处理器。

也就是说 mbed 所使用的二进制文件并没有特别的地方,那它的存储器是如何实现的呢?当它运行了我的用户程序后,存储器功能是否还存在呢?其实在 LPC1768 板子的背面还可以看到很多芯片,存储器的功能就是它们实现的。每次用户按下复位按钮的时候,这部分硬件就会把存储器里面的二进制程序通过 LPC1768 的 ISP 模式下载到芯片里面去。所以存储器的这部分功能一直是存在的,也并不是 LPC1768 这个芯片所实现。

最后要提一句的是这个板子在用了一段时间后竟然是温温的,难道主频 96M 有些高?这是我第一次使用唯一一个不太满意的地方。

Integer promotion in C

虽然使用 C 语言已经很长时间了,但对于一些 C 语言的细节一直没有特别的注意,这次就遇到了在表达式中整型精度提升的问题。

问题描述

问题的发现是在一个 C51 的单片机程序中。相关的代码如下:

P4 = ~P4 >> 4;

本来很简单的一个语句,但在 sdcc 下面编译运行后却得到了令我意外的结果。我马上又使用 Keil C 进行了测试,结果就符合我的预期。那么它们的区别到底是什么呢?假如 P4 == 0x0F,那么对于 sdcc 结果是 0xFF,对于 Keil C 的结果是 0x0F,而后者是我想要的。通过对比二者生成的汇编代码,发现 sdcc 的汇编代码很长(20行),而 Keil C 的代码只有 4 行(预料之中),我根本没有仔细分析一下 sdcc 的代码就直接到它们的网站上去提交了一份 bug report。事实证明我有些太草率了。

问题分析

通过这篇文章的标题就可以知道问题的本质是什么,如果我仔细看一下 sdcc 生成的汇编代码,或者哪怕到 sdcc 的论坛上浏览一下:上个月就有个家伙问过类似的问题(虽然是从另外的方面),并得到了很好的解释。很快我的邮箱里面也收到了 Maarten Brock 的回复:

I see nothing wrong here. C integer promotion rules require the P4 value to be upcast to an int and then have its bits inverted. And after that the resulting int is shifted down. Didn't you get a warning about the ~ operator having strange effects on operands smaller than int?

To get what you probably expected, you should either cast the ~P4 value back to unsigned char or assign it to an intermediate unsigned char variable and shift that down in a second operation.

可惜当时我仍然没有立刻领会了这段话的含义,又经过了几次实验才最终搞清楚。在进行 ~P4 » 4 这个运算的时候,由于第一个取反之后还要进行其它的运算,所以必须在运算前提高 P4 的精度,对于前面的实例,P4 的值将在运算前变成 int 类型,在 C51 的环境中就是 0x000F,然后取反再右移就得到了 0xFFFF(包含符号位扩展),重新赋值给 P4 才使得它最终成为 0xFF。而这种行为是符合 C 语言的标准的,也就是说 Keil C 的行为不符合标准。

没过几天,我正好翻看 Linden 的 Expert C Programming,结果也看到了对 integer promotion 的分析,看来我的 C 语言知识还需要再补充一些。BTW,Linden 的这本书真的是非常的精彩,信息量很大,而且讲述也很有趣,非常推荐大家阅读。

Hello Hyde

第一次尝试使用比较流行的静态网页生成工具,记录一下基本操作过程和感受。

安装

安装 hyde 还是比较容易的,首先安装 pip,好像大部分 python 用户都喜欢用这个安装工具:

# apt-get install python-pip

之后安装 hyde 就比较简单了,直接 $ pip install hyde 就可以,而且也会自动解决依赖关系。

配置

建立一个新的项目可以直接用下面的命令:

$ hyde -s myhyde create

这会使用缺省的 layout 布局页面,myhyde 就是项目的目录,里面的内容就已经是一个完整的网站源码了,之后只要在 myhyde 目录执行 $ hyde serve 就可以在 localhost:8080 上看到网站的效果了。

对网站的配置实际上就是对这个示例代码的阅读、理解和修改的过程。逐步修改配置文件 site.yaml,页面布局脚本 layout/*.j2,和最终 content 目录中的 html 文件,以使网站代码符合我的应用。我把整个过程都通过 git 版本控制系统记录了下来,成为另外一个学习笔记。

页面布局脚本是 Jinja 模板,它的网站上有详细的文档可以参考。Hyde的主页上也包含了很多有价值的配置文档。有关 Markdown 的语法结构,可以参考这个

问题

目前虽然网站已经可以上线,但还是有一些问题没有解决:

  1. css 还要继续学习,一些样式还需要调整。

  2. 代码列表和行内代码没有很好的区分,好像还需要额外的过滤器。 (Edit: 增加 Markdown 的 codehilite 扩展,就可以比较好的区分代码列表和行内代码了。)

SSH reverse tunnel

访问 NAT 内部的服务器

直接使用 ssh 命令

A 处的计算机都在防火墙的后面,IP 地址是如 10.88.32.x 的非法 IP,我在 B 处就无法访问它们。 为了可以远程登录 A 处的主机,就要使用 SSH 的反向隧道功能。此时需要 A 处计算机可以直接 访问 B 处的主机,也就是 B 处主机需要有公网 IP。首先是在A处的计算机上执行

$ ssh -N -R 10002:localhost:22 [email protected]

只要保证这条命令一直执行,就可以在 B 处的电脑上打开 10002 这样一个反向隧道,之后只要在 B 处使用

$ ssh my_a_user@localhost -p 10002

就可以连接 A 处的电脑上了。其中 my_a_user 是 A 处电脑的用户名。而我 B 处主机上的 myuser 用户还可以没有合法的登录终端,这样也很安全,万一 B 处电脑重启什么的,还可以让别人 帮我运行这个命令,不用担心告诉他们密码了。

如果希望从别的主机也可以连接 B 电脑的对应端口,还需要修改 sshd 的配置选项:GatewayPorts 为 yes。

使用 tailscale 等私网组网工具

直接使用 ssh 还是比较麻烦,比较好的解决方案是组一个私网,将所有的个人主机都放到一个 独立的网段中。比如可以使用 wireguard 组网,每个主机会新建一个 tun 虚拟网卡,使用 私有 IP 组网。但自己组网需要考虑网络的结构,至少有一台主机要有公网 IP,否则主机之间 还是无法联通。

有些商业的组网工具可以提供数据中转,即使个人没有公网 IP 也可以组网,如 tailscale 和 zerotier 等。对于大部分用户来说免费额度就足够使用了。

使用 cloudflare 的 tunnel

cloudflare 的 tunnel 可以创建个人主机到公网的隧道,一般用来提供 http 服务,能自动 具有 ssl 证书,并提供 DoS 等攻击的防火墙。用它也同样可以暴露内网的 SSH 服务。不过需要 首先在主机安装 cloudflared。如果主机仅支持 IPV6,可以在 cloudflared.service 中的 ExecStart 中增加 --edge-ip-version 6 参数。

接下来在 cloudflare 的仪表盘建立一个新的域名指向(在 tunnel 的配置页面建立一个主机名) 到 SSH 服务。然后就可以这样访问 NAT 后面的主机:

ssh -o ProxyCommand="cloudflared access ssh --hostname %h" [email protected]

或者可以配置 ssh_config 简化命令:

Host host.domain
  User username
  ProxyCommand cloudflared access ssh --hostname %h

cloudflared 命令实际也是打开了一个反向的 ssh 隧道,比如可以指定端口:

cloudflared access ssh --hostname host.domain --url localhost:2222

这样就可以访问本地 2222 端口来连接远程主机了。