构建适用于openwrt的switch-lan-play插件

24 6月

openwrt是一个非常实用的系统,附带的插件可以配合满足不同的需求。

switch-lan-play是一个远程联机的工具,使用时需要一台设备转发switch的网络请求。一般来说使用的时候打开电脑就足够了,如果经常使用或者手边没有电脑,在路由器上运行明显要好很多。

switch-lan-play官方仓库只提供了win、linux和mac的构建,openwrt的需要自己构建。

构建ipk

openwrt的ipk包除了程序本体以外一般还需要配置、启动脚本和描述信息。

先看构建本身,来源还是git,指向switch-lan-play仓库

https://github.com/spacemeowx2/switch-lan-play.git

主要依赖是libpcap,版本号就跟随官方仓库,当前为0.2.3

include $(TOPDIR)/rules.mk

PKG_NAME:=switch-lan-play
PKG_VERSION:=0.2.3
PKG_RELEASE:=1

PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
PKG_SOURCE_URL:=https://github.com/spacemeowx2/switch-lan-play.git
PKG_MIRROR_HASH:=c0c663e3fdc95d6d6e8ab401caa2bfb5b5872e00
#PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)

PKG_LICENSE:=GPLv3
PKG_LICENSE_FILES:=LICENSE.TXT

include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk

CMAKE_BINARY_SUBDIR := build-openwrt

define Package/$(PKG_NAME)
	SECTION:=net
	CATEGORY:=Network
	SUBMENU:=Lan-play
	DEPENDS:=+libpcap +libpthread +libstdcpp +libatomic @!USE_UCLIBC
	TITLE:=Switch Lan Play Client
endef

配置文件主要考虑几个

  • 是否启用
  • 远程服务器IP
  • 远程服务器端口
  • pmtu配置
config switch-lan-play
	option enable 			'0'
	option ifname 			'br-lan'
	option relay_server_host	'127.0.0.1'
	option relay_server_port	'11451'
	option pmtu			'0'

安装的处理主要就是指定各文件位置,这个也是定义在Makefile的

define Package/$(PKG_NAME)/install
	$(INSTALL_DIR) $(1)/usr/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/build-openwrt/src/lan-play $(1)/usr/bin/
	$(INSTALL_DIR) $(1)/etc/config
	$(INSTALL_CONF) ./files/switchlanplay.config $(1)/etc/config/switchlanplay
	$(INSTALL_DIR) $(1)/etc/init.d
	$(INSTALL_BIN) ./files/switchlanplay.init $(1)/etc/init.d/switchlanplay
endef

启动脚本和正常启动一致,只是多了一个配置的读取,配置中只有pmtu是可选的。

run_switch_lan_play()
{
    config_get_bool enable $1 enable
    if [ "$enable" -gt 0 ]; then
	local ifname
	config_get ifname $1 ifname
	local relay_server_host
	local relay_server_port
	config_get relay_server_host $1 relay_server_host
	config_get relay_server_port $1 relay_server_port
	config_get pmtu $1 pmtu
	if [ "$pmtu" -gt 0 ]; then
		PROG="lan-play --relay-server-addr $relay_server_host:$relay_server_port --netif $ifname --pmtu $pmtu"
	else
		PROG="lan-play --relay-server-addr $relay_server_host:$relay_server_port --netif $ifname"
	fi
	echo "switch-lan-play client started."
    else
	PROG="lan-play --version"
	echo "switch-lan-play is disabled. check configuration?"
    fi
}

自动化构建

构建的时候是需要openwrt sdk的,同时考虑到不同硬件情况,如果只是构建一个设备类型的ipk还好,如果要提供给不同设备,构建起来比较麻烦。

要自动化构建的话主要有几个点:

  • 不同的sdk包
  • make config的配置

直接在docker中构建,考虑到需要不同的SDK包,这里直接用docker的构建参数来解决

FROM ubuntu:16.04

RUN apt-get update && apt-get install bzip2 file python gcc g++ libncurses5-dev gawk zip xz-utils wget libgetopt-complete-perl make cmake git -y -qq

ARG sdkURL=https://downloads.openwrt.org/releases/19.07.3/targets/ramips/mt7620/openwrt-sdk-19.07.3-ramips-mt7620_gcc-7.5.0_musl.Linux-x86_64.tar.xz
ENV sdkURL ${sdkURL}
ARG targetFolder=target
ENV targetFolder ${targetFolder}

RUN echo ${sdkURL}
RUN wget -q ${sdkURL} -O /sdk.tar.xz && mkdir /sdk && tar -xf /sdk.tar.xz -C /sdk && cp -R /sdk/openwrt-* /sdk/openwrt-sdk

重新配置feeds.conf


WORKDIR /sdk/openwrt-sdk
RUN cp feeds.conf.default feeds.conf && echo "src-git openwrt_switch_lan_play https://github.com/htynkn/openwrt-switch-lan-play.git" >> feeds.conf

RUN ./scripts/feeds update -a && ./scripts/feeds install -a

config的配置挺花了点精力,因为一般构建都是make menuconfig进入图形化界面选择lan-play的项,但是自动化肯定不能这么弄。

只有先用defconfig生成配置,然后合并我们需要的配置项。找了下linux中有一个merge_config脚本可以实现。

RUN wget https://raw.githubusercontent.com/torvalds/linux/v4.7/scripts/kconfig/merge_config.sh && chmod +x merge_config.sh
RUN make defconfig
RUN echo "CONFIG_PACKAGE_luci-app-switch-lan-play=y" >> .config-fragment
RUN echo "CONFIG_PACKAGE_switch-lan-play=y" >> .config-fragment

RUN ./merge_config.sh -m .config .config-fragment

准备好了直接构建

RUN make package/luci-app-switch-lan-play/compile && make package/switch-lan-play/compile

自定义源服务

构建出的ipk可以直接安装,但是提供在线安装源是最简单的。除了ipk文件本身,另外一个必要的文件就是Packages文件,其中说明了相关包的内容和信息。内容如下:

Package: simple-obfs
Version: 0.0.5-4
Depends: libc, libpthread
License: GPLv3
Section: net
Architecture: aarch64_armv8-a
Installed-Size: 85471
Filename: simple-obfs_0.0.5-4_aarch64_armv8-a.ipk
Size: 86228
SHA256sum: 1de2460ae99c5123b444e961e1f0fd5c6ea378612978fcf408180a5a51530488
Description:  Simple-obfs is a simple obfusacting tool, designed as plugin server of shadowsocks.

要生成这个信息用脚本处理即可。为了方便后期使用,这里就保持一个较好的文件结构。

RUN make package/luci-app-switch-lan-play/compile && make package/switch-lan-play/compile
RUN rm -rf ${targetFolder} && mkdir -p ${targetFolder} && find . | grep lan-play | grep ipk | xargs -I {} cp {} ${targetFolder}
RUN gcc scripts/mkhash.c -o mkhash && mv mkhash /usr/local/bin && chmod +x /usr/local/bin/mkhash
RUN cd ${targetFolder} && /sdk/openwrt-sdk/scripts/ipkg-make-index.sh . >> Packages
RUN find ${targetFolder} | xargs zip -ur target.zip

这样生成的文件就包含了所有必要信息,放在一般的http服务器上即可。

如果要放在Github Pages也行,但Github Pages没有目录浏览功能,看不到有哪些文件。这里可以自己生成,一个python脚本即可。

""" Build index from directory listing

make_index.py </path/to/directory> [--header <header text>]
"""
from __future__ import print_function
import os.path, time

INDEX_TEMPLATE = r"""

<html>
<head>
<title>${header}</title>
<meta name="description" content="${header}"/>

</head>
<body>
    <h2>Index of ${header}</h2>
    <p>
    <table>
        <tbody>
            <tr>
                <th valign="top"></th>
                <th><a href="?C=N;O=D">Name</a></th>
                <th><a href="?C=M;O=A">Last modified</a></th>
                <th><a href="?C=S;O=A">Size</a></th>
                <th><a href="?C=D;O=A">Description</a></th>
            </tr>
            <tr>
                <th colspan="5"><hr></th>
            </tr>
            <tr>
                <td valign="top"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC "
                    alt="[PARENTDIR]"></td>
                <td><a href="../">Parent Directory</a></td>
                <td>&nbsp;</td>
                <td align="right">-</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <th colspan="5"><hr></th>
            </tr>

            % for name in dirnames:
            <tr>
                <td valign="top"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= "
                    alt="[DIR]"></td>
                <td><a href="${name}">${name}</a></td>
                <td align="right">${time}</td>
                <td align="right">-</td>
                <td>&nbsp;</td>
            </tr>
            % endfor
            % for name in filenames:
            <tr>
                <td valign="top"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC "
                    alt="[DIR]"></td>
                <td><a href="${name}">${name}</a></td>
                <td align="right">${time}</td>
                <td align="right">-</td>
                <td>&nbsp;</td>
            </tr>
            % endfor
            </p>
        </tbody>
    </table>
</body>
</html>
"""

EXCLUDED = ['index.html']

import os
import argparse

# May need to do "pip install mako"
from mako.template import Template

def fun(dir,rootdir):
    print('Processing: '+dir)
    filenames = [fname for fname in sorted(os.listdir(dir))
              if fname not in EXCLUDED and os.path.isfile(dir+fname)]
    dirnames = [fname for fname in sorted(os.listdir(dir))
            if fname not in EXCLUDED  ]
    dirnames = [fname for fname in dirnames if fname not in filenames]
#    header = os.path.basename(dir)
    f = open(dir+'/index.html','w')
    print(Template(INDEX_TEMPLATE).render(dirnames=dirnames,filenames=filenames, header=dir,ROOTDIR=rootdir,time=time.ctime(os.path.getctime(dir))),file=f)
    f.close()
    for subdir in dirnames:
        try:
            fun(dir+subdir+"/",rootdir+'../')
        except:
            pass

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("directory")
    parser.add_argument("--header")
    args = parser.parse_args()
    fun(args.directory+'/','../')

if __name__ == '__main__':
    main()

生成效果:https://htynkn.github.io/openwrt-switch-lan-play/openwrt/

发表评论

电子邮件地址不会被公开。