Arch Linux Printer

太久没发博客了,最近家里需要个打印机,发个打印机的配置教程水一水,顺便记录下家里打印机的解决方案。

虽然叫Arch Linux Printer,但并非全是Arch Linux相关。如果有什么不对的地方,请大火嘴下留情qaq

Printer Driver Install

大部分厂商只提供x86的驱动。我们讲述如何在x86上安装驱动。至于arm等设备可以参考brother-in-arms这个项目来

Install CUPS

首先我们需要安装CUPS服务,参考Arch Linux CUPS

Install Provided Driver

一般来说,厂商提供的驱动只有.deb.rpm两种,我们需要自己提取并放到对应目录来实现手动安装(如果你觉得这不优雅,可以自己封个包然后用pacman本地安装)。

例如Brother 2240所提供的驱动,解压.deb包后有如下

1
2
3
4
5
6
7
8
9
10
┬─[nacl@nacl-archlinux:~/D/hl2240lpr-2.1.0-1.i386]─[16时39分24秒]
╰─>$ tree
.
├── control.tar.gz
├── data.tar.gz
└── debian-binary

1 directory, 3 files
┬─[nacl@nacl-archlinux:~/D/hl2240lpr-2.1.0-1.i386]─[16时39分27秒]
╰─>$

解压data.tar.gz后有如下一坨

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
┬─[nacl@nacl-archlinux:~/D/hl2240lpr-2.1.0-1.i386]─[16时43分18秒]
╰─>$ tar -xzvf data.tar.gz
./
./var/
./var/spool/
./var/spool/lpd/
./var/spool/lpd/HL2240/
./usr/
./usr/local/
./usr/local/Brother/
./usr/local/Brother/Printer/
./usr/local/Brother/Printer/HL2240/
./usr/local/Brother/Printer/HL2240/inf/
./usr/local/Brother/Printer/HL2240/inf/setupPrintcap2
./usr/local/Brother/Printer/HL2240/inf/braddprinter
./usr/local/Brother/Printer/HL2240/inf/brprintconflsr3
./usr/local/Brother/Printer/HL2240/inf/brHL2240func
./usr/local/Brother/Printer/HL2240/inf/paperinf
./usr/local/Brother/Printer/HL2240/inf/brHL2240rc
./usr/local/Brother/Printer/HL2240/lpd/
./usr/local/Brother/Printer/HL2240/lpd/filterHL2240
./usr/local/Brother/Printer/HL2240/lpd/rawtobr3
./usr/local/Brother/Printer/HL2240/lpd/psconvert2
./usr/share/
./usr/share/doc/
┬─[nacl@nacl-archlinux:~/D/hl2240lpr-2.1.0-1.i386]─[16时43分46秒]
╰─>$ tree
.
├── control.tar.gz
├── data.tar.gz
├── debian-binary
├── usr
│   ├── local
│   │   └── Brother
│   │   └── Printer
│   │   └── HL2240
│   │   ├── inf
│   │   │   ├── braddprinter
│   │   │   ├── brHL2240func
│   │   │   ├── brHL2240rc
│   │   │   ├── brprintconflsr3
│   │   │   ├── paperinf
│   │   │   └── setupPrintcap2
│   │   └── lpd
│   │   ├── filterHL2240
│   │   ├── psconvert2
│   │   └── rawtobr3
│   └── share
│   └── doc
└── var
└── spool
└── lpd
└── HL2240

14 directories, 12 files
┬─[nacl@nacl-archlinux:~/D/hl2240lpr-2.1.0-1.i386]─[16时44分10秒]
╰─>$
由于解压出来的var是一坨空的,所以我们直接略过,把usr解压出来的一堆放到本地对应目录下,应该就没问题了(

Use Driver in CUPS

驱动有了,怎么用呢?

我们算是成功安装了驱动,如何调用驱动就需要用到CUPS服务。当你连接打印机并配置服务时,会有一些默认的选项提供,但如果没有你要的驱动,CUPS服务也不知道怎么调用打印机驱动,这时我们就需要手动提供ppd文件。部分驱动会在内提供ppd文件,但如果没有提供,你可以尝试去Open Printing官网寻找(如果ppd和驱动对应不上,建议安装Open Printing提供的驱动,有Linux驱动一般都有ppd吧。。。应该)

以CUPS的web网页为例,Linux大部分客户端调用的是CUPS,所以具体过程大同小异。

访问本地CUPS,在Administer页面选择Add Printer,如果本地有可用打印机会在界面上显示,选择即可

(如果需要共享打印机则需要勾选Share This Printer

之后在该界面选择ppd文件即可正常添加打印机

之后你便可以尝试打印

Enhance

p910nd远程打印

细心的你应该发现了,上面Add Printer界面所添加的打印机并非是本地打印机。要达成这个非常简单,你可以使用别的机器通过CUPS服务共享打印机;但我这边是通过wr720n刷openwrt实现远程调用打印机。重复的就不多说了,参考内容如下:

TP-Link WR720N V3 刷OpenWRT(记得看清楚路由器版本,砖了就不好玩了)

老旧设备利用打印机服务实现网络打印,并实现打印机热插拔(这个热插拔实现有点不优雅,详细看下面的)

通过OpenWRT的p910nd实现远程打印,但这有个缺点:无法手动安装驱动(或者说靠client来处理驱动文帝),相当于usbip将原始usb信息传输到服务器(这个比喻可能不太准确,但这个服务传输的就是原始信息)。

讲一下碰到的问题

1. OpenWRT源失效

lede17 后OpenWRT官方好像做过一次迁移,package的目录变了,找到对应目录换源即可

2. usb热插拔后失效

usb热插拔后p910nd会出现无法识别设备的问题,我们要做的就是写一个脚本,当监测到添加usb设备且usb设备就是我们的打印机时重启p910nd服务

/etc/hotplug.d/usb/目录下添加一个脚本20-p910nd并添加可执行权限

脚本内容具体如下:

1
2
3
4
5
6
7
#!/bin/sh
if [ "$ACTION" = "add" ] && [ "$PRODUCT" = "4f9/45/100" ]; then
# 这行可以修改为你自己的打印机名称,也可以删除,不影响使用。用于检测脚本是否生效
echo "`date`: Brother HL2240 added" >> /tmp/printer
# 执行重启服务
/etc/rc.d/S50p910nd restart
fi
其中的PRODUCT变量可以通过dmseg来查看
1
2
3
4
5
6
7
8
9
10
11
root@LEDE:~# dmesg | grep usb
[ 4.795404] usbcore: registered new interface driver usbfs
[ 4.799554] usbcore: registered new interface driver hub
[ 4.804994] usbcore: registered new device driver usb
[ 5.505721] usb 1-1: new high-speed USB device number 2 using ehci-platform
[ 11.334193] usblp 1-1:1.0: usblp0: USB Bidirectional printer dev 2 if 0 alt 0 proto 2 vid 0x04F9 pid 0x0045
[ 11.342768] usbcore: registered new interface driver usblp
[ 83.696068] usb 1-1: USB disconnect, device number 2
[ 83.700043] usblp0: removed
[ 86.382708] usb 1-1: new high-speed USB device number 3 using ehci-platform
[ 86.546432] usblp 1-1:1.0: usblp0: USB Bidirectional printer dev 3 if 0 alt 0 proto 2 vid 0x04F9 pid 0x0045
找到我们想要的设备id,修改为vid/pid/100就好了(应该)

如果没问题的话你重启时会在/tmp/printer文件内看到内容

具体原理就是利用OpenWRT hotplug来监测usb,当符合条件时重启p910nd

AirPrint自动发现打印机

但这个打印机买来是给我家里父母用的

先来简单介绍下家里的网络配置。由于接入了dn11,家里的网络拓扑大概是这么个样子:

通过wireguard连接了一个阿里云的服务器。同时家里没有配备任何的x86服务器,手机的打印机同时缺少驱动(其实应该能找到,但是没有合适的应用),便将CUPS服务安装在阿里云上,通过阿里云调用p910nd提供的服务来实现远程连接打印机,通过CUPS来实现。

CUPS的安装和打印机的连接非常简单,和上面差不多。唯一的问题就是访问权限,这个到/etc/cups/cupsd.conf里修改一下就好了。

如果没问题的话,你现在应该能用pc通过ipp协议实现打印了;但安卓手机还是不能发现,需要我们配置avahi了。我的avahi是布置在OpenWRT上(毕竟总不能配置在云服务器上吧,多少有点神车),下面是代码

1
2
3
4
opkg update
opkg install avahi-daemon
/etc/init.d/avahi-daemon enable
/etc/init.d/avahi-daemon start

按道理来说你现在应该能在局域网内自动发现打印机了,但我的配置多少有点神车,还需要在OpenWRT上手动添加配置文件

/etc/avahi/services下新添加一个文件printer.service并添加可执行权限,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>Remote CUPS Printer</name>
<service>
<type>_ipp._tcp</type>
<port>631</port>
<txt-record>txtvers=1</txt-record>
<txt-record>qtotal=1</txt-record>
<txt-record>rp=printers/Home_Printer</txt-record>
<txt-record>product=(Remote-CUPS-via-OpenWrt)</txt-record>
<txt-record>adminurl=http://172.16.53.253:631/printers/Home_Printer</txt-record>
<txt-record>note=Proxied CUPS Printer</txt-record>
</service>
</service-group>

其中adminurl项是CUPS共享打印机的url,而rp项是打印机的路径,实际上就是adminurl/printers/<打印机名称>。如果少了这项,在部分软件内会表现出能扫描到打印机但添加时会提示ipp 1030无法找到打印机。

现在,你应该能在安卓的打印服务内找到打印机了!

如果安卓设备还是没法找到打印机,可以用tcpdump监听下udp的5353端口,在监听的情况下重启avahi-daemon,或者demsg | grep avahi来查看avahi配置文件是否生效。tcpdump如果能看到以下内容说明没有问题。

1
21:20:07.235221 lan3  Out IP CR6606.lan.5353 > mdns.mcast.net.5353: 0*- [0q] 6/0/0 PTR Remote CUPS Printer._ipp._tcp.local., (Cache flush) TXT "txtvers=1" "qtotal=1" "rp=printers/Home_Printer" "product=(Remote-CUPS-via-OpenWrt)" "adminurl=http://172.16.53.253:631/printers/Home_Printer" "note=Proxied CUPS Printer", (Cache flush) SRV CR6606.local.:631 0 0, (Cache flush) AAAA fdf4:ed14:48ed::1, (Cache flush) AAAA <不给你看的公网ipv6地址>, (Cache flush) A 172.16.53.1 (332)

这里简单介绍下格规约攻击的原理,写的有些非专业且比较意会,只保留了大致思路以及运作原理,如有出入,就是我太菜了QAQ

简单介绍一下,格规约攻击不是对格密码的攻击,而是借助格对相对“传统”密码的攻击(也不一定是密码体系)

什么是格

我们这里提到的格是这样一个东西:

给定n维空间中一组 线性无关 向量,其 整系数 组合构成的集合称为格

例如有这么一个方程 \[ x*M=b\ \] 其中 \[ \mathbf{x} = \begin{bmatrix}x_1,x_2,x_3,\dots,x_n \end{bmatrix}\\ \mathbf{b} = \begin{bmatrix}b_1,b_2,b_3,\dots,b_n\end{bmatrix}\\ M = \begin{bmatrix}\mathbf{a_1}\\ \mathbf{a_2}\\ \mathbf{a_3}\\ \dots\\ \mathbf{a_n} \end{bmatrix} \] 其中的向量\(x\)中的任意元素\(x_i\in N\)所产生的所有向量\(\mathbf{b}\)的集合,我们把这叫做以为\(M\)基的格\(L(M)\)

格规约原理(应该)

应用前提(部分)

如果我们可以列出这个一个方程 \[ \mathbf{x}*M=\mathbf{b}\ \] 且满足以下条件(当然不只这么一点,但这几个是最重要的)

  1. \(\mathbf{x}\)中的任意元素是整数
  2. 矩阵M已知

这种情况下,我们可以尝试用格规约攻击得到目标向量\(\mathbf{b}\)

怎么求\(\mathbf{b}\)

1.存在性证明:这是一个线性方程组,我们也可以把他看成一个坐标转移,把\(M\)看成过渡矩阵,但这里我们的\(\mathbf{x}\)是一个整数向量。\(\mathbf{b}\)是未知的,我们唯一知道的是\(x\)是一个整数向量,对于矩阵\(M\)是已知的。根据上文可知,我们把等式看成坐标转移,也就是说\(\mathbf{b}\)是在空间\(M\)中的,更确切一点的说是\(\mathbf{b}\)在以基为\(M\)的格\(L(M)\)中,其中的基向量是\(M\)中的行向量,我们可以通过用\(M\)中的基向量进行线性组合(其中的系数都为整数,因为格要求是整数的线性组合)后得到\(b\)

那么问题来了,怎么找到\(\mathbf{b}\)

2.寻找目标向量

这里提到几个比较重要

SVP问题

一个格中最常见的问题,就是最短向量问题(SVP,Shortest Vector Problem)。问题的定义是这样的:给定一个基为\(B\)的格 \(L(B)\),找到一个这个格中的一个向量,使得这个向量长度最短。

当格的维数较低是,可以用LLL算法和BKZ算法求出最短向量。

到这,我们已经快要完全掌握了。如果我们要求的向量\(b\)是格中的最短向量,是不是就可以通过LLL或者BKZ求出向量\(b\),那么怎么确保\(b\)是最短向量?

高斯期望(高斯启发式)

高斯期望(高斯启发式)可以求出最短向量问题,具体证明可以自行查找,结论如下:

假设L是n维格,高斯所期望的最短的长度是 \[ \sigma(L) = \sqrt{\frac{n}{2\pi e}}(Det(L))^{\frac{1}{n}} \] 如果我们能够让格的期望最短长度大于或者远大于我们的目标向量,我们就可以用算法得到最短向量即我们的目标向量\(\mathbf{b}\)

我们来总结下应用前提:

1.存在方程\(\mathbf{x}*M=\mathbf{b}\),且向量\(\mathbf{x}\)中的元素为整数,矩阵\(M\)已知。

2.矩阵\(M\)的维度较小(一般在几十维到几百维)。

3.矩阵\(M\)的高斯期望大于目标向量\(\mathbf{b}\),即\(\sigma(M) \gtrsim |\mathbf{b}|\)

配平技巧及攻击示例

以下展示了一个格规约攻击的示例,包含了构造、配平。如有出入,就是我太菜了QAQ。

拿我最近打的比赛举例:

nctf-绮云

我们可以得到多组相同私钥的rsa。n,e是2048位,d是928位且是复用的,题目就不详细说了,我们这里只举例

对于一组RSA,有 \[ e*d = 1 + k*\phi(n)=1-k*(p-1)*(q-1)=1-k*(N-(p+q)+1)=1-k*N+k*(p+q-1)=-k*N+(k*c+1) = -k*N +c \]

化简成 \[ k_i*N_i+e*d = C_i \] (反正k是整数就对了,不用在意正负)

其中,C的位数大概是 \[ \log_2{k}+\log_2(p+q)=\log_2(o+q)+log_2(d) \approx 1952 \] 我们可以反复退出进入得到多组N,e

然后得到这样一个格,其中系数\(K\)是我们自己决定的 \[ \begin{bmatrix} k_{1} & k_{2} & \cdots & k_{n} & d\end{bmatrix} \cdot \begin{bmatrix} N_{1} \\&N_{2} \\ && \ddots \\ &&& N_{n} \\ e_{1} & e_{2} & \cdots & e_{n} & K \end{bmatrix} = \begin{bmatrix} C_{1} & C_{2} & \cdots & C_{n} & Kd \end{bmatrix} \]

思考,我们要让格的期望最短向量尽可能大,同时让目标向量尽可能小,就需要取一个合理的\(K\)

我们发现,当\(logKd\lesssim logC_i\)时,\(Kd\)项对目标向量长度的大小影响极小,但能够显著增加格的高斯期望。

但当\(logKd \gg logC_i\)时,\(Kd\)项对目标向量长度的大小起主导作用,即\(|\mathbf{b}| \approx K*d\),此时增加\(K\),目标向量长度增长速度就会快于高斯期望增长的速度。

所以当\(Kd \approx C_i\)时是最合适的

再拓展一下就是

目标向量中的每一项大小接近是最合适的(偷懒不证明,嘻嘻)

在这题中,我们让最后一项与前项接近,右边目标向量的长度大概是1952位,格的期望长度是\(\frac{n*2048+1024}{n+1}\)

所以有不等式 \[ \frac{n*2048+1024}{n+1} \gtrsim 1952 \] 解得\(n \geq 10\),所以我们取出10组数据构造格即可得到d,当然n取得越多正确率越高吧

总结

  • 这个格构造的时候,我们让目标向量的最后一项的位数尽可能接近\(C_i\)(因为\(K\)是我们自己取的参数),当最后一项远小于前面项时,他的变化对向量长度影响是极小的,但当它接近或是超过时,就会对目标向量的长度起主导作用。所以在构造格时,我们会尽可能的让目标向量内的元素处在同一数量级,我们把这个技巧叫做配平。(上述提到的只是其中一种配平操作)
  • 补充:对于没有K时,我们可以参考:https://ctf-wiki.org/crypto/asymmetric/rsa/d_attacks/rsa_extending_wiener/,给格右乘一个配平矩阵,对得到的新矩阵做运算,然后对得到的向量乘配平矩阵的逆得到真正的目标向量。

Why make it ?

最近在折腾协会的网络(主要是柏师傅)。刚搬到新家时,因为大伙工作的区域和路由器摆放的位置有点远,所以采取了用光纤将工作区和路由器连接的方式;但这有个小问题,光纤经过的拐角有点多,导致光损偏大,在路由器看来就是接口仰卧起坐,抖动严重。

很巧,工作区也有个网线接口,于是采取eoip将两块分隔的区域连接,目前看来效果不错(虽然中间也碰到了些问题就是了,这以后再说)。然后问题来了,我们需要在ax lite上部署两个container服务,一个是负责校园网登陆的,否则无法与对端连接;另一个是ddns的服务,其实一开始是准备用Ros自带的脚本的,但Cloudflare在国内会有访问问题,而阿里云的需要计算,所以采用container。

于是在一个夜晚一个想法诞生了

柏师傅:要不试试用python调RouterOS的api来代替脚本吧,这脚本难写的一批!

我:真的假的,真有活吗?

柏师傅:有活有活!go都有api库,python肯定有!

然后我就被忽悠上船了.jpg

大致思路

我们要做的无非就是两件事

  • 起个python容器
  • 跑python脚本

首先,先找个封装好的api库,我这边用的是librouteros https://github.com/luqasz/librouteros

OK,库有了,该打包python容器了。。。

真有这么简单吗?

容器打包

惊喜?!

然后我就惊喜的发现,alpine打包的带python的容器要50MB.。。。

这ax lite的ROM也就128MB,这怕不是根本跑不起来。。。

还是翻翻github吧,应该也有人闲着蛋疼缩过

然后我就找到了这个神奇的项目

tiny-python-docker-image

man!What can I say?

但这个项目有个小问题就是这个scratch镜像啊啥也没有,有些库会直接报错

换成alpine的话会加体积,在x86下会从23MB来到30MB左右

但万幸的是,在arm下体积会回到22.8MB左右,还好

pip在拉💩!

OK,python容器解决了

吗?

当我用pip安包时发现即使我卸载了pip,镜像的体积还是来到了32MB。。

🌿,之前做的都白干了,安装的pip在到处拉💩

之前也考虑过手动复制库到python目录下的site-packages中,但这样不太优雅,说到底最好还是pip,或者更好的方法。

是时候问问米奇喵喵屋了。

诶🤓!还真有。

用dive看看在哪拉的一拖然后手动扬掉。

好嘛,扬了!

1
2
3
4
RUN rm -rf /usr/lib/python${PYTHON_VERSION}/site-packages/pip* \
/usr/lib/python${PYTHON_VERSION}/site-packages/setuptools* \
/usr/lib/python${PYTHON_VERSION}/site-packages/pkg_resources* \
/usr/lib/python${PYTHON_VERSION}/ensurepip

其中ensurepip是自带的,但我们应该用不到pip了,或许后续会用到,但先扬了先。

然后我们就得到了一个非常小的镜像

好耶!

0%