在openwrt下安装vlmcsd

网上有很多openwrt安装vlmcsd的方案,比如编译源代码或添加opkg源,通过opkg安装。本文选择了第三条路,直接使用wind4在github提供的release,结合openwrt的几个简单配置,获得局域网免配置kms环境。

  • 测试环境

    项目 说明
    设备型号 phicomm k2p A1
    cpu型号 mips 1004Kc
    openwrt版本 19.07.3
    内核版本 4.14.180

    使用vlmcsd的release是vlmcsd-1113-2020-03-28-Hotbird64,直接下载二进制包。

  • vlmcsd配置说明

    • 官方文档

      我的关注点1:New users should simply run the program without any parameters.。大意是vlmcsd免配置直接运行。
      我的关注点2:Is there an easier way than using OSPP and SLMGR?Yes and no. …… Since this involves DHCP and DNS ……if you are using an open source router firmware like OpenWRT or DD-WRT, it is easy to customize DHCP and DNS.
      大意是如果客户端想不调用各种复杂命令,则需要配置dhcp和dns,并且在openwrt环境下的配置很容易。
    • 探索vlmcsd-floppy

      好奇心驱使,想看看官方是怎么配置vlmcsd的,所以盯上了vlmcsd-floppy。虚拟机通过软驱加载,即可启动服务,单核、16MB内存、无硬盘。
      # 内核版本
      $ uname -a
      Linux vlmcsd.localdomain 3.12.60-Hotbird64 #19 Fri Jun 17 15:45:16 CEST 2016 i686 uClibc-ng/Linux
      # 网络服务
      $ cat /etc/inetd.conf
      21 stream tcp6 nowait.30 root /bin/ftpd ftpd -w /
      23 stream tcp6 nowait root /bin/telnetd telnetd -i
      # vlm*文件
      $ find / -name vlm*
      /var/run/vlmcsd
      /var/run/vlmcsd/vlmcsd.pid
      /etc/vlmcsd.ini # 配置文件
      /bin/vlmcs # 符号链接,指向/bin/vlmcsdmulti-x86-musl-static-threads
      /bin/vlmcsd # 符号链接,指向/bin/vlmcsdmulti-x86-musl-static-threads
      /bin/vlmcsdmulti-x86-musl-static-threads
      # 进程情况
      $ ps | grep vlm
      130 1 vlmcsd ? 0 284 124 0:00 /bin/vlmcsd -e -i /etc/vlmcsd.ini
      175 132 root 136,0 0 720 120 0:00 {exe} grep vlm
      # 网络端口监听情况
      $ netstat -ltpn
      Active Internet connections (only servers)
      Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
      tcp 0 0 0.0.0.0:1688 0.0.0.0:* LISTEN 130/vlmcsd
      tcp 0 0 :::21 :::* LISTEN 119/inetd
      tcp 0 0 :::23 :::* LISTEN 119/inetd
      tcp 0 0 :::1688 :::* LISTEN 130/vlmcsd
      经查询,/bin/vlmcsd的调用参数意义如下:
      -e:日志在终端输出;-i:指定配置文件。
      /etc/vlmcsd.ini文件内容:
      LogVerbose		= true
      MaxWorkers = 4
      ConnectionTimeout = 2
      PidFile = /var/run/vlmcsd/vlmcsd.pid
      User = vlmcsd
      Group = services
      FreeBind = true
      ......
      # 此处省略序列号等信息
      ......
      Listen = ::
      Listen = 0.0.0.0
      结合openwrt环境,考虑2个问题,一是相关文件的保存位置,比如日志、pid文件等,/var/目录是个不错的选择;二是用户名和用户组的问题,需要在系统中添加相应的用户和组。

      注:此配置文件未指定监听端口,默认是1688,openwrt配置dhcp和dns时会用到。

  • openwrt配置说明

    • 思路

      根据vlmcsd配置说明,在openwrt环境中需要完成如下工作

      1. 选择合适的二进制可执行文件
      2. 获取vlmcsd.ini文件(可选)
      3. 使vlmcsd命令能够运行(解决可能存在的ldd问题,添加相关的用户和组)
      4. 使vlmcsd能够开机启动(配置service或修改/etc/rc.local文件)
      5. 配置dhcp和dns(可选)
    • 二进制可执行文件的选择

      wind4提供的release,binaries.tar.gz文件包含cpu+glibc各种组合的编译结果,还提供动态库和静态库版本,非常贴心。
      根据cpu型号和glibc的实现,选择binaries.tar.gz中的文件夹是:binaries/Linux/mips/little-endian/musl/,包含3个文件:

      文件名 说明
      vlmcs-mips16el-musl 客户端程序,可用于验证
      vlmcsd-mipsd16el-musl 服务端程序,单核版
      vlmcsdmulti-mipsd16el-musl 服务端程序,多核版

      如果是日常使用,建议只选择单核版的服务端程序,因为占用空间比多核版的服务端程序小。

      注:该二进制包因为含有*.exe文件,为杀毒软件所不容。

      注:k2p-A1版的cpu是4核,但用户能够使用的rom空间不到16M,仍建议使用单核版服务端程序。

    • 获取vlmcsd.ini文件(可选)

      前面提到,用户可免配置直接运行服务端程序,所以此步骤可选。
      根据用户需求vlmcsd.ini的选取可分为3个层次:

      1. 不需要vlmcsd.ini文件
      2. 精简配置:官方在虚拟机版本中提供vlmcsd.ini(需要修改用户名和用户组)
      3. 完整配置:官方在github仓库中提供,在/etc/目录下(用户根据需求自行修改)
    • vlmcsd命令的运行问题

      因涉及到cpu架构、内核版本、glib实现等问题,使用的二进制文件不一定能正常运行,需要解决一些问题,比如动态链接库的问题。以本文的软硬件环境为例,执行该文件后,会出现报错信息:

      $ ls -l /tmp/vlmcs* # 查看文件位置及权限
      -rwxr-xr-x 1 root root 56707 Jul 22 20:07 /tmp/vlmcs-mips16el-musl
      -rwxr-xr-x 1 root root 39579 Jul 22 20:07 /tmp/vlmcsd-mips16el-musl
      -rwxr-xr-x 1 root root 74835 Jul 22 20:07 /tmp/vlmcsdmulti-mips16el-musl
      $ /tmp/vlmcsd-mips16el-musl # 运行
      -ash: /tmp/vlmcsd-mips16el-musl: not found

      网友提供了宝贵的排错思路。使用strings命令:

      # 执行strings命令
      $ strings vlmcs-mips16el-musl | head
      /lib/ld-musl-mipsel.so.1
      _fini
      __libc_start_main
      _ITM_deregisterTMCloneTable
      _ITM_registerTMCloneTable
      __deregister_frame_info
      __register_frame_info
      _Jv_RegisterClasses
      libgcc_s.so.1
      libc.so

      # 查看/lib/ld-musl*文件
      $ ls -l /lib/ld-musl*
      lrwxrwxrwx 1 root root 7 May 17 02:32 /lib/ld-musl-mipsel-sf.so.1 -> libc.so

      可以看出,vlmcsd-mips16el-musl命令在执行的时候查找的链接文件是/lib/ld-musl-mipsel.so.1,而openwrt提供的文件是/lib/ld-musl-mipsel-sf.so.1。照猫画虎,创建符号链接,再次执行vlmcsd-mips16el-musl命令,成功。

      $ cd /lib
      $ ln -s libc.so ld-musl-mipsel.so.1
      $ /tmp/vlmcsd-mips16el-musl # 运行
      $ ps | grep vlm
      16090 root 956 S /tmp/vlmcsd-mips16el-musl
      16092 root 1216 S grep vlm
      $ netstat -ltpn | grep 1688
      tcp 0 0 0.0.0.0:1688 0.0.0.0:* LISTEN 16090/vlmcsd-mips16
      tcp 0 0 :::1688 :::* LISTEN 16090/vlmcsd-mips16
    • vlmcsd命令开机启动

      直接或优雅,修改/etc/rc.local文件或配置service,任君选择。
      为了保持可执行文件在设备重启之后存在,需要把文件拷贝至/bin//sbin//usr/sbin/目录。以service方式举例:

      $ cat /etc/init.d/vlmcsd
      #!/bin/sh /etc/rc.common
      START=90
      STOP=20

      USE_PROCD=1
      NAME=vlmcsd
      PROG=/usr/sbin/vlmcsd # 这是个符号链接

      start_service() {
      procd_open_instance
      procd_set_param command "$PROG"
      procd_append_param command -l syslog # 如果不记录日志,此行可省
      procd_close_instance
      }

      stop_service() {
      /usr/bin/killall $NAME &>/dev/null
      exit 0
      }

      # 还需要执行命令确保开机启动
      $ service vlmcsd enable
      # 验证
      $ service vlmcsd start
      $ ps | grep vlm
      $ service vlmcsd stop
      $ ps | grep vlm
      $ reboot
      $ ps | grep vlm
    • 配置dhcp和dns

      官方文档的要求:

      1. dhcp服务分配ip地址时,需要分配一个dns domain name,即hostname.domain-suffix(假设domain-suffixlan,一台设备的hostnamepc1,那么它的dns domain namepc1.lan);同时,客户端的dns应指向内部dns服务。
      2. 内部dns服务需要配置一条srv记录。这条记录需要在zonelan内完成。

      openwrt默认完成了几乎所有工作,用户仅需做的就是确定domain-suffix、确定vlmcsd服务端口,以及添加srv记录。以本文的软硬件环境为例:

      项目 说明
      domain suffix lan
      vlmcsd端口 1688
      srv记录(dnsmasq格式) srv-host=_vlmcs._tcp.lan,OpenWrt-k2p.lan,1688,0,100

      注:Openwrt-k2p是路由器的hostname,OpenWrt-k2p.lan是完整的域名。如果kms服务在其他设备上,则需替换为该设备的域名;客户机必须通过dhcp获取ip,才能拥有合规的domain-suffix并能够被内部dns解析。

      注:srv记录的添加位置是/etc/dnsmasq.conf。dnsmasq的配置原理,可参考我的另一篇文章。

  • 验证

    dns解析验证(windows)

    > nslookup -type=srv _vlmcs._tcp.lan
    服务器: UnKnown
    Address: fdd3:6f8:3f04::1

    _vlmcs._tcp.lan SRV service location:
    priority = 0
    weight = 100
    port = 1688
    svr hostname = OpenWrt-k2p.lan
    OpenWrt-k2p.lan internet address = 192.168.1.1

    dns解析验证(linux)

    $ nslookup -q=srv _vlmcs._tcp.lan
    Server: 127.0.0.53
    Address: 127.0.0.53#53

    Non-authoritative answer:
    _vlmcs._tcp.lan service = 0 100 1688 OpenWrt-k2p.lan.

    vlmcs命令验证

    $ ./vlmcs-mips16el-musl 192.168.1.1
    Sending activation request (KMS V6) 1 of 1 -> 00000-00000-000-000000-00-0000-0000.0000-0000000 (0000000000000000)
    # 并非全0,此处做了隐藏处理:)

    windows免配置自动激活

    > slmgr /ckms # 清除kms服务器配置,设备将自动寻找kms服务器
    > slmgr /ato # 执行激活

    无截图,在家庭局域网内测试有效。

  • 小结

    篇幅有点长,短的步骤是

    1. 下载合适的可执行的二进制文件
    2. 解决二进制文件执行时(可能)存在的动态链接库问题
    3. 配开机启动
    4. 配dns,添加srv记录
    5. 验证

    为什么不直接使用网友提供的ipk文件?
    是一种执念吧,因为openwrt官方的opkg库不提供,个人偏向使用官方提供的内容,又懒得制作ipk文件,所以折腾了一把。