Proxmox中LXC容器中docker调用宿主机的显卡加速

刚整了个AgentDVR,里面设置支持GPU解码,于是寻思着整一个,因为J4125的CPU带6路视频录像确实有点吃力,即使是使用了摄像头的stream2,用的是低分辨率的视频流来进行分析,对这个轻量级的CPU来说还是有点吃力。

于是进行了一番Google之后,顺利实现,下面记录一下过程。注意的是,我这里使用的是intel的核显,也就是vaapi,如果是AMD或者Nvidia的显卡的话,肯定会有点不一样,具体的差别需要继续搜索。

宿主机安装驱动

首先,安装显卡驱动和相关的查看工具

apt install i965-va-driver intel-media-va-driver vainfo

根据包的说明i965-va-driver是给Intel G45 & HD Graphics的显卡驱动,而intel-media-va-driver是8代之后的显卡驱动,可以根据实际情况酌情选择。至于vainfo,就是查看相关信息的工具。安装之后执行vainfo,可以看到显卡的加速信息:

root@pve4:~# vainfo
error: can't connect to X server!
libva info: VA-API version 1.10.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_10
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.10 (libva 2.10.0)
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 21.1.1 ()
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            : VAEntrypointVLD
      VAProfileMPEG2Main              : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointEncSliceLP
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointEncSliceLP
      VAProfileJPEGBaseline           : VAEntrypointVLD
      VAProfileJPEGBaseline           : VAEntrypointEncPicture
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP
      VAProfileVP8Version0_3          : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileHEVCMain10             : VAEntrypointVLD
      VAProfileVP9Profile0            : VAEntrypointVLD
      VAProfileVP9Profile2            : VAEntrypointVLD

能看到显卡支持的编码,就算是成功了。这时候,可以在母机的/dev/dri/文件夹下面看到以下内容:

root@pve4:/etc/pve/lxc# ls -als /dev/dri
total 0
0 drwxr-xr-x  3 root root        100 Mar 12 16:22 .
0 drwxr-xr-x 23 root root       5140 Mar 17 07:40 ..
0 drwxr-xr-x  2 root root         80 Mar 12 16:22 by-path
0 crw-rw----  1 root video  226,   0 Mar 12 16:22 card0
0 crw-rw----  1 root render 226, 128 Mar 12 16:22 renderD128

将显卡透传给LXC容器

先给上两个参考文档:

简单来说,就是直接用文本编辑器修改lxc容器的配置文件,加上这么一块

lxc.cgroup2.devices.allow: c 226:0 rwm
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create=file

根据proxmox论坛里面的说明,如果是proxmox 6或者之前的,就用lxc.cgroup。如果是Promox 7或者之后的,就用lxc.cgrpup2。保存退出。

启动LXC容器,再看看/dev/dri/就能看到已经挂载了:

root@ispy:~# ls -als /dev/dri
total 0
0 drwxr-xr-x 2 root   root          80 Mar 17 09:44 .
0 drwxr-xr-x 8 root   root         520 Mar 17 09:44 ..
0 crw-rw---- 1 nobody nogroup 226,   0 Mar 12 08:22 card0
0 crw-rw---- 1 nobody nogroup 226, 128 Mar 12 08:22 renderD128

然后,就是最后一个问题,权限问题,由于lxc容器有隔离,从上面的结果可以看到card0和renderD128被映射成了nobody:nogroup的ownership。这时候就有这么个几种解决办法:

简单粗暴,母机对两个设备给与666的权限

在母机上,直接运行

chmod 666 /dev/dri/card0 /dev/dri/renderD128

使得显卡所有人可以读写。但是这种方法存在一定的安全隐患,所以用来测试配置是否成功的时候可以用,测试OK的话,应该换个别的方法来赋予权限。

idmap+usermod

思路是这样,lxc容器有个设定,叫做idmap,用来控制容器内部的uid和gid如何映射到母机上对应的部分的。例如这个参考:https://bookstack.swigg.net/books/linux/page/lxc-gpu-access

首先,考虑到两个设备默认的权限是660,所以我们有几个方向:

  • 将LXC容器中需要调用显卡的用户映射为母机的root(明显有严重的安全隐患,而且无法处理多个用户需要调用显卡的情况,pass)
  • 修改/dev/dri/card0 /dev/dri/renderD128的ownership,然后和上面一样将LXC容器中需要调用显卡的用户映射为这个新的owner(也还行,但是同样无法处理多用户同时调用,而且母机系统的变动比较多)
  • 将LXC容器中的video组和render组映射到母机的video和render组,然后将需要调用显卡的用户都加入这两个组(不错,但是对于不同的系统,就需要检查对应的/etc/group,并进行对应的调整)

我选择第3种方法。

首先,要确认一下系统的video组和render组,首先是母机的,因为系统都是proxmox(debian),所以gid理论上都是一样的,video的gid是44,render是103:

root@pve4:/etc/pve/lxc# cat /etc/group
……
video:x:44:root
……
render:x:103:root
……

然后就是检查LXC容器的用户组,我用的是Ubuntu20.04,video是gid是44,render是107:

root@ispy:/# cat /etc/group
……
video:x:44:
……
render:x:107:

准备工作就做好了。接下来关掉容器,直接用文本编辑器修改LXC容器的配置文件,加入这么一块内容:

lxc.idmap: u 0 100000 65535
lxc.idmap: g 0 100000 44
lxc.idmap: g 44 44 1
lxc.idmap: g 45 100045 62
lxc.idmap: g 107 103 1
lxc.idmap: g 108 100108 65427

下面给一点解释:

lxc.idmap: u 0 100000 65535		//映射LXC容器中的uid,将容器中[0-65535)映射为母机的[100000-165535)
lxc.idmap: g 0 100000 44		//映射LXC容器中的gid,将容器中[0-44)映射为母机的[100000-100044)
lxc.idmap: g 44 44 1			//映射LXC容器中的gid,将容器中[44-45)映射为母机的[44-45)
lxc.idmap: g 45 100045 62		//映射LXC容器中的gid,将容器中[45-106)映射为母机的[100045-100106)
lxc.idmap: g 107 103 1			//映射LXC容器中的gid,将容器中[107-108)映射为母机的[103-104)
lxc.idmap: g 108 100108 65427	//映射LXC容器中的gid,将容器中[108-65535)映射为母机的[100108-165535)

然后就是要配置/etc/subgid文件,添加以下内容:

root:44:1
root:103:1

最后,把LXC容器开起来,将需要调用显卡的用户加入两个组:

root@ispy:/# usermod -G video root
root@ispy:/# usermod -G render root

执行测试

测试的方法和母机差不多,都是用vainfo来检查,或者使用ffmpeg来测试,但这两个都需要安装一堆软件包,所以这时候,先给容器打个快照。

vainfo的方法可以参考母机,不同的发行版有不同的包管理器,安装vainfo然后运行就能看到结果了。

另外一个方法是使用ffmpeg,这个更接近实际应用,毕竟很多应用也是通过调用ffmpeg来执行编解码的操作。具体ffmpeg的使用方法可以参考官方的文档

这里给出比较有用的一个参考:

ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi -i input.mp4 -f null -

这样可以让ffmpeg调用vaapi来进行解码,并且不输出任何东西,如果能够顺利解码,那就算是成功了。

LXC透传给Docker

透传给Docker的部分不算非常困难,只需要在docker-compose文件里面加上这么一节就可以透进去了:


version: '2.4'
services:
  agentdvr:
    image: doitandbedone/ispyagentdvr
    restart: unless-stopped
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 8090:8090
      - 3478:3478/udp
      - 50000-50010:50000-50010/udp
    volumes:
      - ./ispyagentdvr/config:/agent/Media/XML
      - ./ispyagentdvr/media:/agent/Media/WebServerRoot/Media
      - ./ispyagentdvr/commands:/agent/commands
    devices:
      - /dev/dri:/dev/dri

但是我们遇到了和LXC透传的时候一样的问题,文件权限的问题。ispy提供的docker镜像是基于Ubuntu18.04的,


root@34c54716eee7:/# ls -las /dev/dri
total 0
0 drwxr-xr-x 2 root   root        80 Mar 17 17:44 .
0 drwxr-xr-x 6 root   root       360 Mar 17 17:44 ..
0 crw-rw---- 1 nobody video 226,   0 Mar 12 16:22 card0
0 crw-rw---- 1 nobody   107 226, 128 Mar 12 16:22 renderD128
root@34c54716eee7:/# cat /etc/group 
root:x:0:
……
video:x:44:
……
messagebus:x:102:

容器里面就没有render组,root用户也不在两个用户组里面。于是还得自己build一下镜像……

root@ispy:~/agentdvr# cat build/Dockerfile 
FROM doitandbedone/ispyagentdvr
RUN     groupadd -g 107 render
RUN     usermod -g 44 root
RUN     usermod -g 107 root

完了之后就可以在docker 容器中调用GPU进行加速了。

Linux上iptables端口触发拦截

之前整过在RouterOS上异常的访问触发防火墙拦截ip地址访问,就一直想給VPS套上这种拦截策略,以提高安全性,拦截那些奇奇怪怪的扫描,最近偶然看到了iptables里面的一个模块——ip_recent。

这个模块现在已经改名了,叫做xt_recent,可以达到我所想要的目的,这里记录一下用法:

xt_recent

首先,检查一下模块的情况,用modinfo来看看模块的情况

root@ferrets:/proc/net/xt_recent# modinfo xt_recent
filename: /lib/modules/5.10.0-9-amd64/kernel/net/netfilter/xt_recent.ko
alias: ip6t_recent
alias: ipt_recent
license: GPL
description: Xtables: "recently-seen" host matching
author: Jan Engelhardt jengelh@medozas.de
author: Patrick McHardy kaber@trash.net
depends: x_tables
retpoline: Y
intree: Y
name: xt_recent
vermagic: 5.10.0-9-amd64 SMP mod_unload modversions
sig_id: PKCS#7
signer: Debian Secure Boot CA
sig_key: 4B:6E:F5:AB:CA:66:98:25:17:8E:05:2C:84:66:7C:CB:C0:53:1F:8C
sig_hashalgo: sha256
signature: 54:BB:49:31:44:96:65:97:63:67:BA:20:96:4A:85:29:C6:F2:0C:19:
69:FC:31:34:C7:1E:82:9C:13:90:80:E2:7C:9B:2E:46:1F:32:46:A3:
E0:29:55:01:E4:0E:24:5A:EE:67:C2:6D:45:16:ED:0A:51:AC:CE:A7:
66:F4:CE:3D:2E:F4:13:32:23:87:0C:A2:77:3D:72:99:96:CB:36:6E:
3C:43:15:52:8E:F5:59:31:1B:A1:4F:2D:B2:08:81:AC:F7:B3:0D:80:
D7:0E:DD:78:94:50:F9:8A:CA:3F:5C:6D:AB:4A:B9:E3:94:87:64:7F:
97:08:4F:4A:D3:7E:44:54:8F:F3:03:B8:A8:48:8E:5D:7C:5C:9F:FE:
4E:49:60:63:57:EC:62:57:0C:5C:9F:1F:36:FE:D3:E6:EF:F3:AB:C5:
D2:A4:0E:9C:B2:89:52:55:8A:1F:BF:92:DE:30:19:61:75:A6:22:BC:
A4:DD:2D:B7:8B:74:65:61:A6:4D:75:0E:9B:05:EB:33:79:46:88:13:
71:A3:3F:5C:4B:3C:11:85:EF:B0:F9:CD:45:DE:28:12:84:EB:D1:79:
32:38:19:D3:9F:55:7D:01:27:6C:A2:FB:96:18:7D:30:4E:F7:B4:4F:
33:DA:B6:5D:A2:F9:5E:B0:D2:17:4D:14:12:39:D7:00
parm: ip_list_tot:number of IPs to remember per list (uint)
parm: ip_list_hash_size:size of hash table used to look up IPs (uint)
parm: ip_list_perms:permissions on /proc/net/xt_recent/* files (uint)
parm: ip_list_uid:default owner of /proc/net/xt_recent/* files (uint)
parm: ip_list_gid:default owning group of /proc/net/xt_recent/* files (uint)
parm: ip_pkt_list_tot:number of packets per IP address to remember (max. 255) (uint)

xt_recent上记录ip地址和RouterOS的addresslist设定稍微有点不一样。xt_recent有个参数ip_list_tot,这里会指定单个列表中,能够记录的ip地址的最大的数量,只要列表没满,就会一直留在列表里面;而RouterOS的addresslist会有个timeout的设定,如果超时了就会自动从列表里面移除。这样就导致两者的记录和调用逻辑稍微有点不一样:

  • xt_recent是匹配策略就记录下ip,然后在拦截策略读取ip列表的时候再指定时间区间。
  • RouterOS是匹配的时候就定义一个timeout,然后拦截策略不需要考虑老旧数据的问题。

具体孰优孰劣这个不同人有不同看法,这里就不作太多比较。

要注意的是ip_list_tot默认大小是100,我个人感觉是不是非常够的,于是打算修改一下这个限制。

具体当前的值可以在/sys/module/xt_recent/parameters/ip_list_tot看到,直接用cat来读出来就行。

如果你也觉得默认的列表只有100的容量不是很够,可以参考下面的部分来修改ip_list_tot的值

首先把xt_recent这个mod卸载掉,如果出现提示说这个mod在用导致无法卸载的话,就先检查一下是不是iptables或者ip6tables已经存在调用,可以先把策略删掉,完了再加回来。

首先,把xt_recent停掉。

modprobe -r xt_recent

然后,在/etc/modprobe.d/下面新增一个xt_recent.conf,内容如下:

options xt_recent ip_list_tot=8192

新增完毕之后,再重新加载xt_recent

modprobe xt_recent

最后,检查一下是否已经生效

cat /sys/module/xt_recent/parameters/ip_list_tot

完毕之后,就可以着手开始调整iptables了。

iptables

设计思路可以参考之前RouterOS的部分,但是要作一些修改,因为拦截两种坏东西的时长是不一样的,在Linux上要拆分成两个list,所以,iptables里面INPUT chain可以这样设计:

  1. 允许RELATED,ESTABLISHED
  2. 允许受信任的源
  3. 拦截坏东西的ip地址
  4. 拦截未知访问的ip地址
  5. 标记扫描端口的坏东西的ip地址
  6. 放通正常的服务
  7. 标记其他未知访问的ip地址
  8. INPUT chain默认行为是DROP

这里拿未知访问的来做例子:

# 4.拦截未知访问的ip地址
iptables -A INPUT -m recent --update --seconds 86400 --name UnknownConnection --rsource -j DROP
……
……
……
# 7.标记其他未知访问的ip地址
iptables -A INPUT -m recent --set --name UnknownConnection --rsource -j DROP

这里简单介绍一下几个参数:

-A INPUT :这个策略添加在INPUT chain中
-j DROP :跳转至DROP,即直接丢弃包,不做任何回应
-m recent :调用xt_recent模块
--update :更新最后一次见到的时间
--seconds 86400:指定只检查86400秒就是24小时内的部分,这里的单位是秒
--name UnknownConnection :指定检查名称为UnknownConnection列表
--rsource :指定为源地址匹配
--set :将地址添加到列表中

其他用法的话,这里有篇文章,讲述的比较详细,可以作为参考。

配上之后,可以在/proc/net/xt_recent/文件夹里面看到所有的列表,可以直接用cat或者less等工具来读取。

列表里面的内容

结束

从此,服务器的安全性得到了一定的提升,至少能挡一下扫描什么的了。至于说WAF什么的……先靠Cloudflare吧。

哦,对了,ip6tables可以用一样的方法来加强抗扫描的能力。

追加1

上了这个拦截之后,发现邮箱被jetpack提醒网站下线的邮件填满了。花了一段时间检查之后,终于发现之前放通的部分是使用了ctstate NEW+limit这种,导致无法匹配到tcp reset的包,最后发来reset包的cloudflare服务器就被当作是坏家伙而屏蔽了。加上允许reset包的策略就可以解决这个问题。

iptables -A INPUT -p tcp -m tcp --tcp-flags RST,PSH,ACK RST -m limit --limit 64/sec -j ACCEPT

追加2

如果需要手动操作清单里面的ip地址,可以直接用echo来添加和删除:例如

echo +10.10.10.10 > UnknownConnection #将10.10.10.10添加到列表中
echo -10.10.10.10 > UnknownConnection #将10.10.10.10从列表中移除
echo / > UnknownConnection #清空整个列表

通过DHCP指定mtu

起因

家里的Proxmox母机开了VXLAN的SDN,但是由于vxlan隧道需要吃掉几十个字节作为包的头,导致vxlan的子网里面必须将mtu缩小至1450(母机之间互联用的是1500),但是每次开虚拟机就要手动改mtu这个非常的不友好。

在网上搜索手动指定mtu,文章全部都是使用静态的ip地址,在进一步搜索的时候,发现需要修改Linux的dhcpclient配置,在配置文件里面看到,在客户端发送dhcp请求的时候,是包含接口mtu信息的。

这样就有趣了。

那是不是DHCP服务器可以指定客户端的接口mtu呢?那就不需要我一个一个手动修改了。

进行一番搜索之后,果然发现DHCP里面指定了一个option 26,可以定义接口mtu。而RouterOS也支持自定义dhcp options,官方的wiki里面有关于option的写法。

开搞

配置过程中充满了曲折,我尝试在winbox里面添加option,根据教程,我尝试在value里面填入1400,报错,然后尝试填入0x5aa(1450的十六进制值),也不行。然后我发现,填值据然要加上单引号,于是填入‘1450’,过了。

然而事情并不顺利,我在客户端通过DHCP拿到一个奇怪的mtu,43525。当时我就蒙圈了,这啥情况?

于是我胡乱填了更多的值,得到了更多奇奇怪怪大的一批的mtu值。着实搞不明白,然后仔细看了一下winbox中给的rawvalue,看着怎么这么眼熟,好家伙,这不是把字节的顺序给反过来了吗!

本来应该是05 aa,结果变成了 aa 05

我再确认一下整个活

90000转成十六进制实际上是 01 5f 90,结果变成了 90 5f 01

确认之后,就可以根据需要的raw value反推需要填的值。我们需要 05 aa ,就将 aa 05转换成十进制,得出43525,填入之后得到正确的raw value。

得到正确的raw value。

经测试,能够正常获取到1450的mtu。

报告Bug

这明显是有问题啊,我就去给mikrotik提了个请求,得到回复说马上就修。

mikrotik确认了这个故障,说准备修复。

继续阅读官方wiki

后来仔细阅读了一下官方的wiki,里面提到确实可以用0x来输入十六进制的值,也不用用单引号括住。那为啥我输入0x5aa报错?再来一次的时候发现……0x05aa是完全没问题的,但是0x5aa就不行。

开头的0不能省略

看着顺眼多了。后续等官方修复这个Bug之后或许可以换回去’1450’,这样就更直观了。

openwrt 国内镜像源

原文:https://mirrors.tuna.tsinghua.edu.cn/help/openwrt/

由于某些众所周知的原因,openwrt直接从国外源下载的时候通常都会出现缓慢,短线之类的情况。清华大学的同学十分友好地建立了软件源,如此一来,软件的安装就变得友好了很多~

原文可能是由于字符之类的原因导致命令明显的不对,稍作修正,就得到下方的命令:

cp /etc/opkg/distfeeds.conf /etc/opkg/distfeeds.conf.backup
sed -i 's/downloads.openwrt.org/mirrors.tuna.tsinghua.edu.cn\/openwrt/g' /etc/opkg/distfeeds.conf

完了之后就可以十分愉快地安装软件包了~

为RDP启用显卡加速,提升远程桌面效果

参考:https://www.orgleaf.com/3771.html

在为虚拟机添加了虚拟显卡之后,虚拟机的图形性能大大提升,但是远程桌面似乎没什么两样。稍作一番Google之后,找到打开RDP调用显卡的教程:

RDP启用显卡加速

打开电脑的组策略管理器(运行gpedit.msc

按顺序打开文件夹 “计算机配置->管理模板->Windows组件->远程桌面服务->远程桌面会话主机->远程会话环境”。在文件夹目录内能看到一个叫“将硬件图形适配器应用于所有远程桌面服务会话“的设置。从”未配置“改为”已启用“。

提升传输帧率

这一步需要修改注册表,在[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations]新增一个DWORD项,名称为“DWMFRAMEINTERVAL”,值为0000000f(16进制)或者15(10进制)。可以参照教程从regedit.exe进去一步一步添加,或者是直接用.reg修改。

.reg的内容如下:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations]
"DWMFRAMEINTERVAL"=dword:0000000f

复制内容,用笔记本文档保存为一个.reg文件,双击导入即可。

完毕后重启生效。

调整后远程桌面的效果显著提升,就算是跑点小黄油之类的也不会觉得画面卡卡的了。

为proxmox启用intel核显的虚拟化

参考:https://cetteup.com/216/how-to-use-an-intel-vgpu-for-plexs-hardware-accelerated-streaming-in-a-proxmox-vm/

家里跑着两个proxmox的虚拟化服务器,其中一个是用NUC6i5SYK跑的,有张Iris 540的核显,之前一直没用上,前阵子某天看到有视频UP主在讲Nvidia逐步支持消费级显卡的显卡虚拟化,能让虚拟机共享母机的显卡。同时提到了,Intel的显卡也有一样的功能,而且发布了挺久了,于是我稍作Google,找到教程并成功开启。

不过这个功能要求CPU是Intel酷睿5代以后的CPU或者Xeon E3 v4之后的CPU,同时,也被称为GVT-g。比起PCI直通显卡,这个功能让母机依然能够使用该核显,也能给多个虚拟机共享核显的资源,对我们这种抠抠索索的穷逼友好了不少。

在Proxmox上启用PCI直通和GVT-g

首先,命令行登陆proxmox的母机,进行下一步操作前建议先执行一次apt更新,确保系统是最新的状态。

第二步,修改/etc/default/grub文件,修改GRUB_CMDLINE_LINUX_DEFAULT的参数,在后面添加“intel_iommu=on i915.enable_gvt=1”,就像这样:

GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on i915.enable_gvt=1"

然后保存,执行update-grub以更新grub的配置。

参考中在执行update-grub之后,在这里会重启检查dmesg,个人推荐放做完全部修改之后再重启,可以少重启那么一次……

第三步,修改/etc/modules文件,插入以下内容,启用PCI直通和GVT-g

# Modules required for PCI passthrough
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

# Modules required for Intel GVT
kvmgt
exngt
vfio-mdev

最后重启服务器,重启完毕之后,可以使用这个命令检查一下是否有输出,如果没有输出的话,可能在哪里出了问题。

dmesg | grep -e DMAR -e IOMMU

给虚拟机添加虚拟显卡

当母机支持显卡虚拟化之后,就可以给虚拟机添加虚拟显卡了,全程可以在web页面完成操作。

在虚拟机-硬件里面添加PCI设备

选择完成虚拟化的显卡

选择MDev类型,这时候有两个选择,根据原文,两个其实性能没什么差别,就是V5_8能有2个,而V5_4只能有1个……

这里要注意的是,根据参考,勾选“主GPU”的话,会使得Proxmox的console失效,这个我没验证。

完了之后重启虚拟机,然后就能在设备管理器里面看到显卡了,打上补丁之后,就能正确显示显卡型号了。

因为是Intel的显卡,用windows自带的驱动更新就可以自动下载驱动并安装了。

大功告成~

我还看到个为RDP启用显卡的教程,明天整一整。

windows无法解析域名

参考:https://answers.microsoft.com/en-us/windows/forum/windows_7-networking/windows-7-browsers-unable-to-resolve-domain-names/77e1f86d-618d-4d37-b693-8c37bed3b28d

今天不幸办公的PC炸了,不得不重置win10,在重置之后出现了一个非常诡异的问题,浪费了我一整个下午。

这个故障的特征是windows不会向DNS服务器查询域名,手动用nslookup是可以正常获取到解析结果,但是除了nslookup以外,ping之类的工具、浏览器都会直接返回一个无法解析地址的错误。在整个过程中,用wireshark抓包会发现系统根本没有向dns服务器发起解析的请求。

经过一番google(垃圾百度),找到一个问题,就在上面的参考,里面有位Lakusus的老哥给出了一个答案,就是电脑的计算机名丢了,一检查,果然如此,在重新设置上计算机名并重启就正常了。

顺便一说,我在设置的时候不能在win10的“设置”程序里面修改,只能去控制面板-系统那里修改。

希望能对某位不幸的朋友提供一些帮助。

在openwrt路由上运行shairplay作为远程音箱

参考:

  1. https://blog.csdn.net/luotong86/article/details/53207387
  2. https://zhuanlan.zhihu.com/p/103121214

因为手里空闲着一条漫步者的M16,现在我又用着iPhone,就想尝试一下airplay,没想道意外的简单,这里做个简单的记录。

首先,使用opkg更新软件包缓存

opkg update

然后,安装kmod-usb-audio:

opkg install kmod-usb-audio

这将安装usb声卡的驱动,如无意外,就可以看到/dev/audio的出现,这意味着系统能够正常识别到声卡。如果没认出来,那可能是系统尚不支持声卡,推荐换一只,毕竟重新移植驱动这种事情还是比较麻烦的,如果官方没有Linux驱动那就更没希望了。

下一步就是安装shairplay:同样非常简单,因为有对应的luci管理界面,顺便装上。

opkg install luci-app-shairplay

接着就可以去网页进行管理了:

这里只要简单的修改一下Airport Name,AO Driver选择alsa,然后勾选上enabled,保存并应用即可。

下一步就能在播放器上选择Airport后,点击播放就能听到音箱响起来啦~

建立私有docker镜像源

参考:https://linuxhint.com/setup_own_docker_image_repository/

最近非常着迷docker和kubernetes这玩意,感觉完全就是未来发展方向,于是决定好好研究一番。

有时候服务器处于内网环境,不好上网扒镜像,又或者说,由于一些众所周知的原因,从docker hub扒镜像会非常的缓慢,所以,我觉得有必要建立一个本地的docker镜像源。

建立方法

建立方法很简单,docker官方提供了一个镜像方便人们建立私有的镜像源。

根据参考文档,可以直接用一条命令来将服务跑起来,就像这样:

docker container run -d -p 5000:5000 --name registry -v<br> ~/docker/registry:/var/lib/registry registry

不过我个人推荐使用yaml文件+docker compose,方便日后维护,也习惯一下这种方式,为以后上kubernetes做准备。我就弄了一个,内容如下:

[root@docker-repo ~]# cat repo.yaml 
version: "2.4"
services:
  private_docker_repo:
    image: library/registry:latest
    ports:
      - "5000:5000"
    restart: unless-stopped
    volumes:
      - /storage:/var/lib/registry

然后,只要用

docker-compose -f repo.yaml up -d

就可以将服务跑起来了。-f参数是用来指定yaml文件,如果使用了docker-compose.yml作为文件名,可以省略掉。不过推荐自定义文件名,这样就可以将很多yaml放在同一个文件夹了。

日后如果registry镜像有更新,或者是修改什么设置,只要修改好配置文件,再pull一次和up一次即可,docker-compose会处理好更新的。

例子中,我的给机器挂了个100G的盘,挂在了/storage,到时候,数据会存在这里。

DNS修改

然后就是处理dns或者hosts,根据参考文档来看,不做也行,不过做了的话,可以少打几只字。( =ω=)

推荐做dns强制解析,那就不需要和原文一样去修改hosts。以后镜像源迁移、或者是docker母机增加减少之类的就不需要每次都处理hosts文件了。

举个例子,我修改DNS,将pdr(private docker registry)解析为镜像源服务器地址。

在docker母机上增加源

默认情况下,docker只会从docker hub拉镜像,要指定似有的源,就要修改一下配置文件。配置文件是/etc/docker/daemon.json,如果没有的话,就新建一个,添加以下内容:

{
"insecure-registries": ["pdr:5000", "192.168.11.207:5000"]
}

然后,重启docker。(对,是要重启docker的,所有容器都会重启)然后就可以在客户端使用这个似有源了。

对于在私有源上的镜像,用法和官方源差不多,只不过用户名变成了“服务器ip:端口”,于是,镜像名称格式如下:

IP:PORT/IMAGE_NAME:TAG_NAME

比如说,mariadb,在docker hub上,镜像的名称就是mariadb,或者其他用户的话就是xxx/mariadb(xxx是用户名)。但是在私有源上,就是192.168.11.207:5000/mariadb,或者在处理了dns或者hosts之后,可以用pdr:5000/mariadb。(看,可以少打很多个字!)

至此,似有镜像源搭建完成!

至于镜像源里面有什么镜像和有什么tag这个我暂时还没发现,暂时只发现在/storage/docker/registry/v2/repositories能看到有啥镜像。根据官方文档的说明:可以使用 http://服务器IP:5000/v2/_catalog 查看都有什么image。

列出镜像

做了个小脚本,放在docker-compose文件挂载的目录里面,我的是/storage,然后就可以直接列出镜像和列出指定镜像的tag了

#!/bin/bash
case $1 in
	"")
		ls -l docker/registry/v2/repositories/ | grep "drwx" | awk '{print $9}'
		;;
	*)
		ls -l docker/registry/v2/repositories/$1/_manifests/tags/ | grep "drwx" | awk '{print $9}'
		;;
esac

效果如下图

RouterOS上抵挡扫描的防火墙策略

背景

因为家里的宽带是找电信要了公网IP地址的,所以互联网可以直接访问到我作为出口的RouterOS,而众所周知,互联网上扫描机不知何几,被盯上了的话也是一件相当麻烦的事。

起因

之前在玩RouterOS上的防火墙的时候,发现有一个动作,叫做“add src to address list”,能够将包的源地址添加到某个列表中。俺寻思了一下,发现这能够很好的抵挡扫描机,思路是这样的:

防火墙策略

建立防火墙策略,指定一些经常被扫描的目的端口,然后,防火墙的动作是将包的源地址添加到一个叫做sniffer的地址列表中,设定有效时间为30天,然后,让防火墙直接丢弃来自这些地址的包,这样如果某个机器尝试扫描我的出口,触发了这个机制,那这个机器就会直接被ban掉30天。

命令行的话,添加起来是这样的:

/ip firewall filter add action=drop chain=input comment="drop sniffer" in-interface=China-Telecom src-address-list=sniffer
/ip firewall filter add action=add-src-to-address-list address-list=sniffer address-list-timeout=30d chain=input comment="mark sniffer" dst-port=22,23,876,3306,3389,137,139,445,5001,6379,27017 in-interface=China-Telecom log=yes log-prefix=sniffer protocol=tcp
/ip firewall filter add action=add-src-to-address-list address-list=sniffer address-list-timeout=30d chain=input comment="mark sniffer" dst-port=22,23,876,3306,3389,137,139,445,5001,6379,27017 in-interface=China-Telecom log=yes log-prefix=sniffer protocol=udp
/ip firewall filter add action=add-src-to-address-list address-list=sniffer address-list-timeout=30d chain=input comment="mark sniffer" dst-port=2323,5555,80,81,37215,8000,8080,8081,8291,8443,53 in-interface=China-Telecom log=yes log-prefix=sniffer protocol=tcp
/ip firewall filter add action=add-src-to-address-list address-list=sniffer address-list-timeout=30d chain=input comment="mark sniffer" dst-port=2323,5555,80,81,37215,8000,8080,8081,8291,8443 in-interface=China-Telecom log=yes log-prefix=sniffer protocol=udp
/ip firewall filter add action=drop chain=input comment="drop sniffer" in-interface=China-Telecom src-address-list=sniffer

然后放着一阵子,就会在address list里面看到大量的IP地址。

继续改进

如果想要更加全面的保护,可以选择在防火墙上添加允许一些正常的策略,比如说,允许每秒不超过20个echo-request的icmp包啊之类的,然后在防火墙的末尾,加一条策略,将其他未知的包,都当作扫描机处理,一律有杀错无放过。

但是有时候,ban了对方的ip,也就意味着无法访问对方的IP地址,因为回包会被防火墙丢弃。这时候就要额外的添加一条策略,插在丢弃sniffer的策略的前面:

action是accept就可以了。这样如果是主动对外访问的话,回的包要么是related,要么是established,这样就可以正常访问被ban掉的ip。至于说udp访问可能没有这个状态标记……先暂时忽略吧,出现问题再继续改进。