7
11
2018
14

Linux 下获取文件的创建时间

其实 Linux 是支持文件的创建时间的呢。不过不是所有文件系统都支持,比如 ext4、xfs、btrfs 都支持,zfs、vfat、ntfs 不支持。

但是呢,用户基本上是看不到的。文件系统有记录,但是没有 API 可以获取到这个数据。所以你用 stat 命令的话,会看到「创建时间」一行总是「-」。用 debugfs 搞 ext4 是可以的,但是那个需要 root 权限,并且一不小心会搞坏文件系统。

最近,我阅读内核源码时,忽然发现内核已经通过 4.11 版本引入的 statx 系统调用支持获取创建时间了。字段名里用的是 btime(birth time),没有用 crtime(creation time),也没有用大写的 Btime 呢。

但是 glibc 并没有支持,所以要用 syscall 函数来调用。也不是很复杂。不过我正着手用 Rust 实现的时候,却在内核源码树里找到了 samples/statx/test-statx.c 这么个文件。原来有现成的啊!

gcc 编译一下,还真好用:

>>> statx /
statx(/) = 0
results=fff
  Size: 224             Blocks: 0          IO Block: 4096    directory
Device: fe:01           Inode: 96          Links: 17
Access: (0755/drwxr-xr-x)  Uid:     0   Gid:     0
Access: 2018-07-11 13:33:08.659477830+0800
Modify: 2018-03-30 15:06:02.645864827+0800
Change: 2018-03-30 15:06:02.645864827+0800
 Birth: 2017-06-19 21:07:53.653467000+0800

2019年09月03日更新:现在(coreutils 8.31)stat 命令已经支持创建时间了。

Category: Linux | Tags: linux
6
14
2018
3

递归遍历目录:Python vs Go vs Rust

群友提出了一个简单的任务:递归遍历一个很大的目录,根据文件名数一下有多少 JPEG 文件。怎么最快呢?然后他用了 Go 语言实现。

我忽略想起 Python 3.5 的 What's New 里提到,他们优化了 os.scandir 使得目录遍历快了好几倍(PEP 471)。其核心思想是:不进行不必要的 stat 系统调用,因为读目录获得了不少信息,原来都是丢弃掉了,现在改成了通过 DirEntry 对象来返回。这些信息包括文件名等,刚好有我们需要的。

于是 Go 做了这个优化没有呢?

翻了一下代码。Go 自带的实现位于 src/path/filepath/path.go 文件中。可以看到,它对每一个文件都 lstat 了。后来一阁指出,不仅如此,而且它还莫名其妙地对目录下的文件名进行了排序

呃,前者可以说是疏忽了,毕竟 Python 也是直到 3.5 才优化的。可是,它排那个序干嘛呢……

然后我又想到,Rust 那边如何呢?

结果是,Rust 对它所包含的东西非常审慎,标准库里并没有递归遍历目录的函数。那我们自己写一个?才不呢,用第三方库啦!可以看到,它也是返回 DirEntry 对象的。

后来了解到,Go 也有一个第三方的实现 godirwalk,对这些细节进行了优化。

光是了解实现不够。我们让它们来比试一下吧。顺便,把 find 和 fd 也拖进来好了。

任务:数一数一个拥有近万文件的目录下有多少 JPEG 文件。

实现代码:walkdir-test

结果:

   Rust: top:    4.78, min:    4.72, avg:    4.90, max:    5.46, mdev:    0.17, cnt:  20
 Go_3rd: top:    7.71, min:    7.64, avg:    7.79, max:    8.41, mdev:    0.16, cnt:  20
   find: top:   11.49, min:   11.32, avg:   11.76, max:   14.18, mdev:    0.59, cnt:  20
     fd: top:   18.17, min:   15.18, avg:   21.29, max:   29.94, mdev:    3.84, cnt:  20
     Go: top:   21.08, min:   20.91, avg:   21.28, max:   22.70, mdev:    0.37, cnt:  20
 Python: top:   29.66, min:   29.51, avg:   30.43, max:   35.84, mdev:    1.45, cnt:  20
Python2: top:   30.37, min:   30.10, avg:   30.85, max:   33.15, mdev:    0.75, cnt:  20

Rust 如预期一样是最快的。Go_3rd 就是那个第三方库的实现,也非常快的。fd 是 Rust 实现的,目标之一是快,但是这次并没有比老牌的 find 快。Go 自带的那个实现,十分令人遗憾地连 find 都没比过呢,不过还是比 Python 快了不少。Python 2 这次终于没有跑在 Python 3 前边了(虽然差距很小),我猜是 PEP 471 那个优化的功劳。

对了,还有代码行数:

  15 Python/walk
  29 Rust/src/main.rs
  30 Go/walk.go
  33 Go_3rd/walk.go

Rust 竟然不是最长的。不过确实是字符数最多的。

话说 Go 的 } 竟然也是有规定的,结构体的不能另起一行写,只能跟 Lisp 的风格那样堆在一行的尾巴里。

PS: 没想到之前给 swapview 写的 benchmark 程序在另外的项目里用上了呢,果然写东西还是通用些的好。


更新:在群友的提示下,我找了一个更大的目录来测试,结果很不一样呢。这次遍历的目录是 /usr,共有 320397 个文件。

     fd: top:  265.80, min:  259.84, avg:  273.89, max:  319.76, mdev:   15.03, cnt:  20
   Rust: top:  269.98, min:  266.86, avg:  272.82, max:  282.84, mdev:    4.17, cnt:  20
 Go_3rd: top:  361.17, min:  359.05, avg:  363.82, max:  370.22, mdev:    3.31, cnt:  20
   find: top:  454.03, min:  450.79, avg:  458.51, max:  467.31, mdev:    5.08, cnt:  20
 Python: top:  624.80, min:  615.73, avg:  630.67, max:  640.88, mdev:    6.79, cnt:  20
     Go: top:  890.03, min:  876.98, avg:  910.63, max:  967.14, mdev:   24.84, cnt:  20
Python2: top: 1171.38, min: 1157.19, avg: 1189.99, max: 1228.09, mdev: 4186.28, cnt:  20

可以看到,唯一的并行版本 fd 胜出了~Rust 版本紧随其后,显然在此例中并行并没有多么有效。Go_3rd 还是慢于 Rust 但也并不多。然后,经过优化的 Python 终于在更大的数据量上明显胜过了 Go 以及 Python 2 这两个浪费了很多系统调用的版本。

Category: 编程 | Tags: python go 编程语言 Rust
5
25
2018
77

这个博客要死了

很早的时候,那个时候我还在读大学,博客火了一阵。

那时候我刚拥有自己的计算机没多久。那时候我才开始在 Linux 系统里摸索着自学编程。犹犹豫豫地,我注册了一个 WordPress 账号。过了一两周的样子,我那个只有「Hello World」的博客随着众多 WordPress 博客一起被墙了。

那么就换一个地方吧。没过多久,我开通了 Google 提供的 blogger 博客。次日被墙。

那个时候,在国内的网站上发布内容还不需要提供手机号,位于国内的网站也不需要备案。所以我找了个国内的服务,也就是由当时我经常上的 Ubuntu 中文论坛所提供的博客服务。我在那里写过几篇不成熟的文章。过了挺长一段时间的。后来,他们宣布中止服务。

我后来就来到了这里,is-programmer.com。那时候这里还挺繁荣的,有好多人在这里写博客。那时候也没有多少垃圾评论。就这么安静地过了很长时间,站长突然联系不上了。再接着就是用户越来越少,垃圾评论越来越多。我挺担心哪天域名过期,然后自己的博客就消失了。还好我之前向站长申请过自定义域名,于是就用上了。使用 JavaScript 做了跳转和替换,Google 说这样子也是可以的,不过百度那边显然不认可这种做法。后来我又担心这VPS到期没人续费。还好这些都没有发生,域名和VPS都还活着。当然为了以防万一我写了个爬虫,把博客数据爬回来做了备份。

再后来,博客挂了差不多一天。我想方设法登录到了服务器上,删除了大量缓存和日志文件,腾出来些磁盘空间,这才又恢复。然后顺便把之前上传的文件也备份了回来,把域名跳转改成了通过301重定向的方式。不过很可惜,百度依旧不懂。

就这样勉强活着吧。我本来想自己写一个博客程序,可生活实在是太累了,就一直也没有写出来。也不太想用静态博客,因为不方便评论。特别是 Disqus 曾经用欺骗的方式拿了我的社交账号又要求注册 Disqus 账号,以及后来默认不允许匿名评论、匿名评论不显示头像,使得我对 Disqus 挺反感的。

而就在前几天,我这博客被入侵了。入侵者篡改了首页。虽然刷新缓存之后就恢复了,但我感觉很不好。

这博客,已经老了。就算我通过各种打补丁的方式,支持 HTTPS,支持 IPv6,更换自己控制的域名,使用脚本更改页面中的旧链接,但是,它还是在一点一点、不可避免地衰老。

Category: 未分类 | Tags:
5
14
2018
24

Windows 10 中配置网络共享

有一个很讨厌的公司叫「深信服」,英文名叫「Sangfor」。它开发的私有协议的 SSL VPN 客户端 EasyConnect 终于支持 Ubuntu 了,然而我没能在 Arch Linux 上正确地把它跑起来。图形界面是 electron 之类的,这部分没有问题。但有一个会往 /usr/share 下写日志的 root 进程,应该是负责真正的 VPN 创建的,死活连不上。

那么就在 Windows 虚拟机里跑吧。所以我的 Linux 系统需要通过 Windows 访问部分网络了。只是 HTTP 的话倒是可以装个 HTTP 代理搞定,但是我还要连 ssh 的。

正文开始了。其实整个过程并不难,关键在于很难找到资料。

首先,当然是给 Windows 一张 host only 的网卡,用于两个系统之间的连接。以及,把那个 VPN 连上。

然后,打开「网络设置」,选择「更改适配器选项」。右键单击要共享的网络适配器(比如此例中是那张 Sangfor VPN 的网卡),选择「属性」。

选择「共享」选项卡,把第一个框给勾选上,下边下拉菜单选择那张 host only 的适配器。确定。

就这样,OK 了。

Windows 10 中配置网络共享

要注意的是,此操作会将网卡的 IP 强制设置为「192.168.137.1」。就像图中可以看到的那样,微软总喜欢「提供策略,而非机制」。假定你是给你的家庭共享。假定你要共享的是 Internet 连接(本例中其实是 VPN 连接)。所以它也假定了你的「家庭」网络中 Windows 可以随意选择 IP 地址,假定你需要 DHCP 服务。

Linux 这边配置起来就容易多了。Virtualbox 的 vboxnet0 接口本来用的是 192.168.56.0/24 网段,但是给它配置另外的 IP 地址,往它里边扔它不了解的目标地址的包,它也不介意的。

sudo ip a add 192.168.137.2/24 dev vboxnet0
sudo ip r add 172.16.2.9/32 via 192.168.137.1

以上给 vboxnet0 添加了 IP 地址,并且让需要走 VPN 的目标地址(172.16.2.9)走 Windows 的网络。

PS: 开着防火墙的话,Windows 10 默认是忽略 ping 的。在防火墙的「入站规则」里启用「文件和打印机共享(回显请求—ICMPv4-In)」之后才能 ping 它。

另见阿森人的《伪·如何在 Linux 下使用深信服 SSL VPN》一文。

Category: 网络 | Tags: 微软 windows 网络
4
6
2018
16

小米 Note 3 令人失望地方

小米 Note 3 入手的时候简单写过一篇文章。现在用了一些天了,有些新的体会,也是我最不满意的地方。

双摄像头看上去很厉害,但是照片大小只有1-2MB,不像我的 Z5C 一样有5-6MB。为什么呢? 在手机上,因为小米相册放大倍数有限,根本看不出来差别。但是传输到电脑上之后可以很明显地看出差别:

小米 vss Z5C

从图中可以看到,小米拍摄的照片(左)不仅比我的 Z5C 的(右)分辨率要低,而且有偏色、模糊不清(照片拍摄的是 Paperlike HD 的 Floyd 模式,所以那些沙粒一样的效果是本来就那样的;背景色有点偏绿也是肉眼所见之状态)。

这意味着,用于记录的时候,比如拍摄白板、幻灯片、小区通知,习惯了 Z5C 之后,用小米很可能在需要的时候才发现根本看不清(我已经有好几张记录用的照片现在才发现基本上是毁了)。

小米摄像头另外有一个大问题:在光照很强的时候(比如晴天室外),摄像头会有反光,在照片中呈现出一个偏绿色的亮点

摄像头反光亮点

之前已经提到过,这扬声器的设计挑握持姿势,很讨厌很讨厌:我左手握持的时候,为了保证手机不在遇到碰撞不稳等情况的时候意外滑落,我会用小指托住底边,刚好堵住扬声器的孔……

小米云同步能是能同步,但是很不及时。一般情况下,我 Z5C 拍好照片过一会儿,就可以在 Google Photos 上看到照片了。小米不知道怎么回事,经常看不到照片,需要手动打开相册然后等一会儿才会有。

啊对了,小米右上角那个天气,也是要点开才会更新的样子……

Category: Android | Tags: Android 手机 小米
3
24
2018
23

小米 Note 3 入手体验

为了对付诸如支付宝、淘宝、摩拜等在我的 Z5C 上特别卡的手机软件,我入手了一台小米 Note 3。

最初的感觉是:很滑,手感很不错。下面指纹识别很方便。

有点大,单手不容易按到对面。因为下巴上都是按键,所以放桌面边缘时不容易拿起来,会误触那些键。不过作为备机,在家的时候放桌面上就好了,解锁直接按,不需要经常拿起来。

没有拍照键,但是可以设置音量当快门用。有快速启动,但是是在系统设置的「手势及快速启动」中配置的。另外有个「街拍模式」,就是拿着手机,长按快捷键开始连拍或者摄像,而屏幕没有任何显示。

拍照默认带水印,可以在选项里关掉。前置摄像头拍照时默认带美颜(i.e. 别当镜子用)。还带了性别和年龄检测,以及我没太搞懂的「魔镜」评分功能。

云存储会存储原始品质的照片,免费空间只有5G,不像 Google 是 10G,并且可以无限量存储高品质照片。黑屏的时候似乎并不会同步照片,反正我等了好久,在网页端没看到。等再次打开相册时,它告诉我正在同步呢。

自带手电筒功能,可配置成亮屏后长按菜单键启动。不能像我那个 Xposed 模块那样,直接从黑屏状态启动。不过也没多大差别。

音质好不好不清楚,反正是够响。不过扬声器位于下边缘右边,手挡到的话会非常影响音质。我用过的 Z5C、Z3C、LT26i 上均没有发现这种事情,倒是我第一个智能手机 E15i 是这样,扬声器在背面,听歌时得俯卧着。

充电很快。剩余一半多的电,开始充电时 5.7V 0.9A,后来到了 6.6V 0.7A。不过使用小米充电器,我的Z5C更快,系统显示充电电流为 1.9A。我原来的充电器给 Z5C 充电时只有 0.9A 的,快了一倍。不过发生了一件令人悲伤的事情——忘记取下我的USB电流电压测量仪,它工作太久,累坏了……

SIM 卡槽需要使用配备的捅针去捅出来。不过需要的时候,最好同时配备一只汉子,或者女汉子,因为真的要用很大力,偏偏捅针就一个圈,细细的,底端也是面积极小的边缘,皮肤不够糙的话很难使上劲。当然也可以想办法,比如把针插好,然后对着桌面使劲磕几下,卡槽就会出来个边了。这体验比起 Z5C 用指甲一剥即开的体验,是有趣不少。

不插SIM卡无法安装未知来源的应用(apk 文件),也不知道这是什么鬼逻辑。小米商店里的东西还比较多的,条码扫描器、Elixir 2、Telegram 都有。HE 的 Network Tools 没有,不过可以去百度那边搜到。Google 应用说是因为授权问题没有,会提供位于百度上的版本。我没试过能不能安装,反正安装了也用不了……

默认浏览器默认为MIUI自己的浏览器,如要更改,需要去「设置」->「更多应用」->右上角菜单「默认应用设置」里修改,不会像 Android 原生系统那样让用户自行选择,也不能通过默认浏览器应用信息里的「取消默认操作」来重置。

主页是类似于 iOS 的:没有下边的「所有应用」界面,只有混杂在一起的应用图标和小部件。最让人受不了的是,应用图标被加了个半径非常大的圆角矩形,还带个白底

顶栏默认不显示通知图标。这样也好,因为放一天之后我一看,近十条没什么用的通知呢……可以设置显示网速,不过不知道是下行速率还是总和。可惜不能显示时间显示秒数。

总体来说,功能挺丰富,但是有些混乱,界限不清。比如两种设置快捷键的途径(相机内、设置内,其实 Android 系统原生快捷键比如截屏也是可以用的,但是设置里是没有的),比如两种设置默认应用的方法。比如到处都是的推广。应用商店里几乎搜任何东西都能看到知乎,搜 Network Tools 能看到 RealCalc。「游戏」应用里竟然有「直播」。建立个放应用的文件夹都能给你推荐应用。说得好听点,叫「紧密集成」,说不好听,就叫「高耦合」。

哦对了,这机器需要保持干燥。也就是说,我洗澡时想听歌还是得带上我的 Z5C。

2018年04月06日更新:续篇《小米 Note 3 令人失望的地方》

Category: Android | Tags: Android 手机 小米
2
14
2018
5

使用 VirtualBox 启动本地磁盘上的其它系统

VBox 可以从一个指向本地硬盘的 vmdk 文件启动虚拟机。

首先,为了避免使用 root 运行 VBox,我们需要给自己访问磁盘的权限。我即将启动的是位于 sda5 上的 openSUSE。它使用 UEFI 启动,所以 UEFI 分区的权限也是需要的。创建 vmdk 文件的时候需要读取分区表,因此,还需要 sda 的权限:

sudo setfacl -m u:${USER}:rw /dev/sda{,1,5}

然后我们创建 vmdk 文件。使用-partitions 1,5选项的话,只有这两个分区能在虚拟机里访问,别的分区读的时候是全零,写入操作会被忽略。-relative选择使用分区设备名(sda1、sda5),这样创建好之后 VBox 不再需要对整块硬盘 sda 的权限了。另外会附带创建一个名字以 -pt.vmdk 结尾的文件。它是单独的分区表。如果是 MBR 启动的话,是可以直接在虚拟机系统里更新引导器的,不影响外边的系统。不过我这次是使用 UEFI 启动,所以用不上了。

VBoxManage internalcommands createrawvmdk -filename hostdisk.vmdk -rawdisk /dev/sda -partitions 1,5 -relative

创建好之后就可以撤销对 sda 的权限了:

sudo setfacl -b /dev/sda

然后去 VirtualBox 界面那边创建新虚拟机,并「启用 EFI」。另外,可以在存储设置里,把「控制器: SATA」的「使用主机输入输出 (I/O) 缓存」启用,似乎这样 I/O 会快一点。

VBox 的 EFI 并不像电脑的那样,按 F12 可以选择启动项。因此,它会启动默认的那个,也就是 /EFI/Boot/bootx64.efi。如果你想启动的系统不是这个的话,就把它的 efi 文件复制过来覆盖它。比如我是这么做的:

cd /boot/EFI/Boot
sudo cp ../opensuse/grubx64.efi bootx64.efi

如果是 Windows 10 并使用 MBR 启动的话,可以在虚拟机里用如下命令更新 MBR,干掉原来用于多启动的 grub:

bootsect /nt60 c: /mbr

做好之后就可以启动啦~

对于设备的权限设置,重启之后会丢失的。需要的时候再加上好了。

PS: openSUSE 自带了 VBox 的驱动啊,不过剪贴板共享不能用,大概只有显示驱动没带上服务。

PPS: 启动没一会儿就通知我更新出现错误,一看软件源设置,果然是 HTTP 的,被垃圾鹏博士劫持了。

Category: Linux | Tags: linux 虚拟机 vbox
2
12
2018
22

大上 Paperlike HD 电子墨水屏开箱体验

刚听说就已心动,无奈当时并不支持 Linux。后来由于一些事情耽搁到现在,终于到手了~

开箱啦

显示器整体尺寸是31cm×27cm,其中显示屏尺寸不到26cm×21cm(请注意:手工测量有误差)。分辨率是2200x1650。也就是200dpi多,和我的 Kindle Paperwhite 一代差不多的。

显示器下方是两个纸盒,里边是Y形线(照片中没有)、简易支架(那根根子)、螺丝和仅几百M的驱动U盘。

附件

Y形线是附加了USB电源线的HDMI线。信号走HDMI,电源走USB,所以需要额外占用一个USB口。当然接充电器上也是可以的,只是在电脑边接个充电器更不方便。

工作时,USB端口的电流为30~50mA左右,并不像说明书上说的需要2A那么多,挺省电的。对比之下,我的罗技鼠标接收器也需要15mA左右的电流呢。

线都接上之后,屏幕会闪几下,然后就可以用了。只是每隔几分钟会弹出提示信息,要求安装并运行所谓的「驱动」。下图是默认的 floyd 模式:

未使用软件,显示的登录界面

为了更多的模式,以及最重要的,别显示那个提示信息,需要安装并运行大上提供的软件。

软件是为 Ubuntu 提供的,但是 Arch 下也可以使用。下载并解包,将得到的三个文件「PaperLikeHD」、「ResChange」、「DS.ico」放到/usr/local/sbin/下,然后sudo PaperLikeHD 运行,会弹出一个包含一列按钮的窗口。不给 root 权限是不行的,会什么也不做就退出。

但是这样还不够。我使用的时候它总是报告找不到显示器。客服不肯告诉我它到底使用什么机制检测的,所以我 strace 又反汇编看了一下,最后发现它在找 /dev/i2c-* 设备文件,而我的系统上没有它们。看了一下一堆以 i2c 开头的内核模块,最后发现只要加载 i2c-dev 模块就好了。大上的软件需要一些时间来检测,等一会儿它就会在终端打开出「setting...50」这样的文字,这时就好了。

在台灯下使用火狐发推

过程中我还专门启动到 Ubuntu live 系统里测试来着。后来才知道原来是自己的手速太快,软件还没检测到,其实等等就好 (╯‵□′)╯︵┻━┻

Ubuntu live

从图片中可以看到,floyd 模式的显示很粗糙。这是因为它实际上只有二阶灰阶,通过不同密度的点来近似不同的灰度。虽然显示有很严重的颗粒感,但是它响应飞快,常规打字操作时几乎感觉不到延迟,很适合写作和阅读文本。而真正的二阶灰阶模式 A2,只有黑白两色,虽然依旧反应快速,但是因为非黑即白,只能用来读纯文本,任何阴影或者灰色的字都不好处理。

16灰阶的 A16 模式,显示清晰、层次丰富,但是响应速度非常慢。也不是非常啦,除了屏幕大小外,无论显示效果还是响应速度都跟我的 Kindle 一样的。而与 Kindle 不同的是,它会在更新时将更新区域变黑再显示,造成闪烁。在此模式下使用鼠标非常非常费力,任何非静止的元素(比如火狐载入中的动画、时钟、光标移动)都挺分散注意力的。

以上都是所谓的「可变分辨率模式」。另外有个「固定1100x825模式」,也就是使用一半的分辨率。至于另一半去了哪里,看看它所支持的模式就能猜到了:

  • A5,也就是五灰阶。这是用四个墨滴来显示一个像素,每个墨滴只有黑与白两种状态。
  • A61,所谓的61灰阶。也是用四个墨滴来显示一个像素。不过每个墨滴竭尽所能有16种状态,也不知道大上是怎么组合出这61灰阶的。

也不知道大上为什么把这两种墨滴用法叫作「可变分辨率模式」和「固定1100x825模式」。哪里可变了,又哪里固定了呢?这两种模式切换时,会调用「ResChange」程序,它会影响当前的显示器布局,需要重新使用 xrandr 进行设置。

以下是各种模式显示这个灰阶测试网页的照片:

A2 模式:

A2 模式

A16 模式:

A16 模式

floyd 模式:

floyd 模式

A5 模式:

A5 模式

A61 模式:

A61 模式

半分辨率下,清晰度做出了很大的牺牲。以下是 A16 和 A61 模式显示 PaperLikeHD 软件自身界面的效果对比:

A16 A61

在 A2、A5、floyd 模式下,可以调节对比度,也就是墨滴到底显示为黑还是为白的值,以在显示不同的页面时都能将文本与背景良好区分开。

和 Kindle Paperwhite 不同的是,它没有背光。在晚上的时候,屏幕偏暗,附加一个台灯光源比较好。不过它的屏幕也不像 Kindle 那样偏黄。

这篇文章最终定稿,就是在 PaperLikeHD 上完成的,使用的是 floyd 模式。我个人觉得半分辨率的几个模式很鸡肋。目前觉得,写作用 floyd 模式,文本阅读使用 A2 模式,网页阅读使用 A16 模式,这样最好了~

floyd 模式还有个问题:在显示某些图片时(比如我的 Awesome 桌面壁纸),那些墨滴颗粒会不断地抖动,就像风在吹沙粒一样……

最后,这里是大上的官网链接

Category: 硬件 | Tags: linux 硬件 E-ink 显示器
2
10
2018
3

加固 systemd 服务

最近学 wzyboy 搭了一套 collectd + Graphite + Grafana 监控。collectd 和 Grafana 都比较好搞,Arch 官方源里有。但是 Graphite 就没有了。

我没有使用 Python 2 版、带 Web 前端的 Graphite 包,而是使用 graphite-api 提供 Web API,python2-carbon 存储数据。它们在 AUR 上有,其中 python2-carbon 是相当危险的(现在已经改了)。

为什么危险呢?

首先,最明显的,carbon 服务以 root 用户运行。它本身没有任何使用 root 权限的必要,所以专门创建一个 carbon 用户更好。

其次,它运行起来之后,我发现是监听 0.0.0.0 的。这个也无必要:我的 collectd 就在本地呢。

最后,也是最吓人的:它默认开启了接收 pickle 数据的端口。Python pickle 模块的文档一打开,就能看到红色的警告,告诉人们不能接收不信任来源的 pickle 数据。而我曾经工作过的公司也发生过通过 pickle 注入代码的事情:攻击者发现了一个对外网开放的 Redis 服务,刚好那个 Redis 是给 Celery 用的。攻击者于是往里边写了条自己构造的 pickle,在解析时调用 curl 命令向其服务器报告IP、端口和当前UNIX用户的信息。

这接口,开在外网,就是远程代码招行;开在本地,就是本地提权。很危险的。

为了防止各种漏洞被利用,一个未雨绸缪的办法就是:权限最小化。本来这是件比较麻烦的事情,好在 systemd 提供了许多现成的配置项,使得给 carbon 这种服务加固简单易行。

首先创建用户,写一个 sysusers 文件就可以了:

u carbon - "carbon service" /var/lib/carbon

然后,它需要使用文件系统的某些部分。那么别的就用不着访问了,比如 /home。而 /dev、/tmp 这些,自己用自己的就好。连 / 也不让写,也不允许获取任何新特权了。其实使用 carbon 用户它本来就写不了 / 也没有任何特权了,但以防万一嘛,要是哪里来个本地提权漏洞呢?

[Unit]
Description=Graphite/Carbon
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/carbon-cache.py --config=/etc/carbon/carbon.conf start
User=carbon

PrivateTmp=true
PrivateDevices=true
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
CapabilityBoundingSet=

ReadOnlyPaths=/
ReadWritePaths=/run
ReadWritePaths=/var/log/carbon
ReadWritePaths=/var/lib/carbon

[Install]
WantedBy=multi-user.target

限制文件系统的访问,systemd 配置起来很方便,我打包的时候喜欢尽量加上。

完整的 python2-carbon 服务配置和打包脚本在这里

以及,这里是 Arch Linux 中文社区的编译机的 Grafana

Category: Linux | Tags: Arch Linux systemd linux 安全
1
18
2018
9

嗨 Win10,这是我的浏览器

因为腾讯的关系,不得不使用 Windows。不是QQ也不是RTX,这次 Wine 帮不上忙了。那好吧,SSD + 16G 内存,跑个 Windows 虚拟机也没多大问题。

但是问题来了:我在虚拟机里每次点击链接,会调用安装于 Windows 上的浏览器来访问。可是我登录了各种工作账号的浏览器在外面的自由世界 Linux 主系统里啊。

办法也好想:来一个远程调用,让 Windows 调用咱自己的程序打开链接,然后咱自己的程序再把链接传给外面的 Linux 就好了。理想是美满的,可是 Windows 里设置默认浏览器并不是写个 .desktop 文件那么简单!

在 Google 上找了半天资料(真的花掉了半天!),最终终于确认,需要设置以下一大堆注册表键,Windows 才会认可咱自己的浏览器:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser]
@="RemoteBrowser"

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\Capabilities]
"ApplicationName"="RemoteBrowser"
"ApplicationIcon"="C:\\RemoteBrowser\\launch.exe,0"
"ApplicationDescription"="RemoteBrowser"

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\Capabilities\StartMenu]
"StartMenuInternet"="RemoteBrowser"

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\Capabilities\URLAssociations]
"https"="RemoteBrowserHTML"
"http"="RemoteBrowserHTML"
"ftp"="RemoteBrowserHTML"

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\DefaultIcon]
@="C:\\RemoteBrowser\\launch.exe,0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\InstallInfo]
"IconsVisible"=dword:00000001
"ShowIconsCommand"="\"C:\\RemoteBrowser\\launch.exe\" --show-icons"
"HideIconsCommand"="\"C:\\RemoteBrowser\\launch.exe\" --hide-icons"
"ReinstallCommand"="\"C:\\RemoteBrowser\\launch.exe\" --make-default-browser"

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\shell]

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\shell\open]

[HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\RemoteBrowser\shell\open\command]
@="\"C:\\RemoteBrowser\\launch.exe\" \"%1\""

[HKEY_LOCAL_MACHINE\SOFTWARE\RegisteredApplications]
"RemoteBrowser"="SOFTWARE\\Clients\\StartMenuInternet\\RemoteBrowser\\Capabilities"

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice]
"Progid"="RemoteBrowserHTML"

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice]
"Progid"="RemoteBrowserHTML"

[HKEY_CLASSES_ROOT\RemoteBrowserHTML]
@="RemoteBrowser"
"FriendlyTypeName"="RemoteBrowser"
"URL Protocol"=""
"EditFlags"=dword:00000002

[HKEY_CLASSES_ROOT\RemoteBrowserHTML\DefaultIcon]
@="C:\\RemoteBrowser\\launch.exe,0"

[HKEY_CLASSES_ROOT\RemoteBrowserHTML\shell]
@="open"

[HKEY_CLASSES_ROOT\RemoteBrowserHTML\shell\open]

[HKEY_CLASSES_ROOT\RemoteBrowserHTML\shell\open\command]
@="\"C:\\RemoteBrowser\\launch.exe\" \"%1\""

相比之下 Linux 只需要以下这么几行:

Version=1.0
Name=Firefox
GenericName=Web Browser
Comment=Browse the Web
Exec=/usr/lib/firefox/firefox %u
Icon=firefox
Terminal=false
Type=Application
MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;
StartupNotify=true
StartupWMClass=Firefox
Categories=Network;WebBrowser;
Keywords=web;browser;internet;

(不过真实的 firefox.desktop 有三百多行,因为各种语言的名字和描述的翻译。)

上边那个注册表文件,引用了一个 exe 文件,和里边的一个图标资源。我不知道图标使用独立的文件可不可以。加个图标并不难,上网搜一下就有了,使用 windres 命令即可。

首先准备好图标文件 icon.ico,然后写一个资源文件:

1 ICON DISCARDABLE "icon.ico"

用 windres 把它编译成 COFF 文件。因为我是在 Linux 上使用 mingw 操作,所以使用的命令叫 x86_64-w64-mingw32-windres。然后把它和其它目标文件链接到一起就可以了。因为我使用的是 Rust,它的 build.rs 脚本不支持目标文件,所以先打包成静态库,然后再链接:

x86_64-w64-mingw32-windres launch.rc -O coff -o icon.res
x86_64-w64-mingw32-ar q libres.a icon.res

然后 build.rs 脚本里说一下:

fn main() {
  println!("cargo:rustc-link-search=native=..");
  println!("cargo:rustc-link-lib=static=res");
}

然后咱的主程序,通过 TCP 把链接发到 Linux,以及 Linux 端的服务,接收链接并打开浏览器,因为很简单很常规,所以这里就不列出来了。有兴趣的去源码仓库看就好了。

exe 编译好之后,扔到之前注册表文件里提及的地方就好。然后双击那个注册表文件将其导入。接下来在默认软件的设置里就能够找到我们的「Remote Browser」了(虽然不知道为什么没有显示指定的名字,而是 exe 文件名)。

另外,那个图标资源,也可以使用 Resource Hacker 把图标文件给弄到 exe 文件里边去。

最后一步,写个用户级的 systemd 服务,把负责在浏览器里打开链接的程序给跑起来~


仓库地址在此。喜欢的话,记得 star 哦~

Category: Linux | Tags: windows 浏览器

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com