OpenWrt的一些心得

最近在折騰OpenWRT,第一次接觸,用的是HLK7688的板子(就是下面這個東西,淘寶找的圖)

這裏寫圖片描述

先說個坑,燒了固件之後,WAN口改變,並不是左邊獨立出來的第一個,我的變成了最右邊的那個。所以,如果通過uboot燒固件,怎麼都不成功的話,多試試其它網口。硬件部分在圖片的基礎上略有改動,這個板子有兩個串口(就圖上的兩個),我的板子把串口2卸了,裝了個數碼管,可以實時統計WIFI設備的連接數量。

好了,我接下來就說說我自己的研究過程心得。

0x01 OpenWrt小試牛刀之環境準備與初次編譯

OpenWrt的準備工作我就不詳細介紹了,我直接說說我自己的環境吧,還有中途我遇到的一些坑。我會給一些參考鏈接,不明白的可以參考別人寫的比較詳細的內容。

1、Linux環境 (Ubunut 16.04)

推薦Ubuntu16.04,我就是使用的Ubuntu16.04,搭配的VMware虛擬機。本來我自己的主機是Kali2016.1_x64,一開始想直接用Kali編譯,結果變異過程特別艱難,頭文件好多函數名不一樣,修改了4、5個頭文件,還是編譯沒出固件,所以不推薦使用Kali,其它的沒用過,看了網上的回饋Ubuntu12.04應該也還可以。

2、安裝依賴庫

apt-get install g++
apt-get install libncurses5-dev
apt-get install zlib1g-dev
apt-get install bison
apt-get install flex
apt-get install unzip
apt-get install autoconf
apt-get install gawk
apt-get install make
apt-get install gettext
apt-get install gcc
apt-get install binutils
apt-get install patch
apt-get install bzip2
apt-get install libz-dev
apt-get install asciidoc
apt-get install subversion
apt-get install libssl-dev

或者

apt-get install g++ libncurses5-dev zlib1g-dev bison flex unzip autoconf gawk make gettext gcc binutils patch bzip2 libz-dev asciidoc subversion libssl-dev

網上很多都少了安裝libssl-dev這個庫,也可能是Ubuntu16.04的需要手動安裝一下,這裏需要注意一點。

3、下載OpenWrt項目

我下載的是 Trunk版

自己想要什麼版本,可以直接上官方找找,鏈接: http://git.openwrt.org/

在Linux系統裏直接git下來就好了

$ git clone git://git.openwrt.org/openwrt.git

4、更新軟件包

進入openwrt項目的目錄執行下面兩條命令

$ ./scripts/feeds update –a
$ ./scripts/feeds install –a.

5、配置編譯配置文件

首先需要生成配置文件,是一個在openwrt根目錄下的隱藏文件“.config”

$ make defconfig

這條命令會檢查編譯環境,如果安裝包沒安裝好,這一步會有提示,然後自行安裝就Ok

接下來就可以開始定製自己想要的標準功能了

$ make menuconfig

這條命令是在控制檯生成的圖形化配置窗口,進入之後就能配置自己的固件了,對應固件的硬件信息,標準軟件包,一目瞭然。熟悉之後,配置完成,保存,會自動在OpenWrt目錄配置隱藏的”.config”文件。接下來就可以編譯了。

6、編譯

簡單介紹幾個常用編譯參數以及效果

$ make     // 直接編譯,全都使用默認參數
$ make -j8     // -j表示啓動多線程編譯,8表示8條線程
$ make V=s // 編譯過程打印輸出變異過程,如果編譯失敗,使用這條命令,可以看到出錯詳細信息,最好和 -j1聯用
$ make package/xxx // 指定編譯軟件包,最終生成*.ipk,在bin/目錄,編譯完成拷貝到路由器使用 opkg install *.ipk進行安裝

生成的文件,在OpenWrt的bin/目錄下,雖然我的板子用的是MT7688,但在實際編譯時我配置的目標是MT7628。在目錄下會生成很多個*.bin文件,燒錄的時候,燒錄openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin

第一次接觸,這裏還有一個點需要注意

在編譯完成之後,如果發現沒有生成想要的openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin這個文件。

可能是因爲生成的包大小超過了,比如說我想直接在路由器裏進行開發,選擇編譯了,編譯出來的包有20+M,但我的路由器是根本裝不下的,OpenWrt項目會自動判斷,就算生成了這個包,你也無法安裝,是無效的,就不會生成這個*.bin文件。所以在自定義配置的時候,還是根據需求自己選擇必須的功能就好。如果真的就想生成這麼大的固件,這個問題我想應該也是可以突破的,不過我還沒有研究。

0x02 如何把自己的程序編譯進固件

既然是做二次開發,那我們總不能寫個程序編譯了一個一個路由器裏把程序拷貝進去,我們就需要把程序一起編譯進固件,燒完路由器,程序也就自然安裝好了。

關於如何把自己寫的代碼編譯到固件裏其實也很簡單。

這裏先推薦兩篇文章

OpenWRT Makefile框架以及Kernel和firmware生成過程分析
http://www.cnblogs.com/sammei/p/3968916.html

OpenWrt上用C來寫一個Helloworld http://scateu.me/2016/12/03/openwrt-helloworld.html

通過上兩篇文章,我再把我汲取到的知識簡要的分享一下,不懂的可以在博客留言

首先,生成*.ipk包的源文件都是存在於package目錄下的

配置.config編譯配置文件的時候,會掃描所有目錄的makefile文件,那麼我們只需要按照OpenWrt給我們的規則來配置makefile文件就行Ok.

我以一個helloword的例子講述一下這個過程。

1、創建一個規範的目錄結構

在package目錄下創建一個helloworld文件夾

openwrt/package/helloworld
├── Makefile                    // 暫且稱爲root_Makefiel
└── src
    ├── helloworld.c
    └── Makefile                // 暫且成爲src_Makefile

在root_Makefile寫入內容 (這裏的root_Makefile表示的是外部的Makefile,注意看上一段的註釋)

include $(TOPDIR)/rules.mk

PKG_NAME:=helloworld
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

# 這裏的宏配置的是在 make menuconfig 中的選項
define Package/helloworld
    SECTION:=utils
    CATEGORY:=Utilities
    TITLE:=Helloworld
endef

define Build/Prepare
    mkdir -p $(PKG_BUILD_DIR)
    $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Package/helloworld/install
    $(INSTALL_DIR) $(1)/bin
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/
endef

$(eval $(call BuildPackage,helloworld))

然後在src/helloworld.c裏寫一個標準教科書版本的 helloword

#include <stdio.h>

int main()
{
    printf("hello world\");
    return 0;   
}

再寫一下編譯程序的src_Makefile

helloworld: helloworld.o
    $(CC) $(LDFLAGS) helloworld.o -o helloworld
helloworld.o: helloworld.c
    $(CC) $(CFLAGS) -c helloworld.c

clean:
    rm *.o helloworld

OK.這樣就可以編譯了

啓動OpenWrt的編譯配置

~$ make menuconfig

我們剛寫好的程序,在選項Utilities->helloworld,選中,保存,退出

執行make,就能直接把程序編譯到固件裏

測試程序也可以先把程序編譯成*.ipk包,然後放到路由器裏opkg install helloworld.ipk先安裝測試一下,再編譯固件。

0x03 自啓動腳本如何編譯進固件

自啓動腳本的編譯也可以按照上面的思路來進行,最後添加到啓動項的時候,只需要在外部Makefile裏添加把腳本拷貝到系統目錄/etc/init.d/的命令就可以,雖然我小測無果,但我相信這個思路肯定沒問題。

我這裏說另一種更直接粗暴簡單的方法。

將腳本文件放到這個目錄下,並且添加可執行權限。

package/base-files/

這是編譯固件的一個基礎文件目錄,就是說,所有固件中都會包含這個文件夾裏的內容。

我就用我的數碼管實時顯示WIFI用戶數量的腳本來說。

我的程序目錄結構是這樣的

/
├── etc
│    └──count_number
└── usr
    └── share
         └──count_number
                 └──count_number.sh

就只有兩個文件

/usr/share/count_number/count_number.sh是我獲取WIFI客戶連接數量並輸出到數碼管的腳本實現

/etc/init.d/count_number 是開機啓動腳本,實際上的開機啓動腳本存在於/etc/rc.d目錄下,這個目錄我們不用管,他會自動幫我們拷貝/etc/init.d/目錄下的文件過去

/etc/init.d/count_number 腳本代碼

#!/bin/sh /etc/rc.common
# Copyright (C) 2017 www.wangsansan.com

START=50

start() {
    /usr/share/count_number/count_number.sh &
}

OK,把文件按照目錄結構放到package/base-files/文件夾下,並添加可執行權限

這樣就完成了。

編譯,就直接把腳本編譯進固件裏了。

0x04 Luci 靜態界面修改

好的,固件定製結束了,那就定製一下web頁面,先登陸到路由器web頁面看看

1、界面底部

這裏寫圖片描述

上圖藍色部分包含超鏈接、版權支持信息文字和版本信息

看到圖,第一個思路,找到Luci的安裝目錄,再從所有文件中搜索上面那串文字,

如果第一次玩OpenWRT不知道Luci安裝目錄,可以先找到index.html文件,因爲Luci使用的是Lua腳本跑的,所以找到之後,cat查看或者用vim打開index.html,就能找到Luci安裝目錄。當然,也可以直接在根目錄“/”執行查找命令,不過時間會比較漫長。

一般來說Luci的安裝目錄都是 “/usr/lib/lua/luci”

執行下面的命令。

root@OpenWrt:~# cd /usr/lib/lua/luci
root@OpenWrt:/usr/lib/lua/luci# find ./ -name "*" | xargs grep -Hn "Powered by"

解釋一下參數含義,find 命令就不說了

xargs 將stdout輸出流測內容傳到stdin當作下一條命令的參數

grep

-H //打印文件名

-n //打印行號

返回結果

root@OpenWrt:/usr/lib/lua/luci# find ./ -name "*" | xargs grep -Hn "Powered by"
./view/themes/bootstrap/footer.htm:17:    <a href="https://github.com/openwrt/luci">Powered by <%= ver.luciname %> (<%= ver.luciversion %>)</a> / <%= ver.distversion %>
root@OpenWrt:/usr/lib/lua/luci#

找到那麼,vim 打開文件 “./view/themes/bootstrap/footer.htm”

修改第17行,對比原文,分析一下這行html代碼什麼意思

## 原文 ##
Powered by LuCI Master (git-17.246.24307-3e1ae70) / OpenWrt Designated Driver r49395

## HTML 標籤,方便觀看,分成三行 ##
<a href="https://github.com/openwrt/luci">
Powered by <%= ver.luciname %> (<%= ver.luciversion %>)
</a> 
/ <%= ver.distversion %>

一眼看過去,嗯,用眼睛翻譯一下

<a href="超鏈接url"> Powered by <變量1> (<變量2>) </a> / <變量3>
變量1 = "LuCI Master"
變量2 = "git-17.246.24307-3e1ae70"
變量3 = "OpenWrt Designated Driver r49395"

且 <變量3> 不包含超鏈接。

既然知道怎麼回事,改起來方法就很多了。

1、可以直接修改變量內容;

2、直接修改此處的html內容;

爲了方便,我就直接修改html吧,超鏈接跳轉到我的博客地址,並且居中顯示

<a href="https://www.wangsansan.com" style="display:block;text-align:center;">Powered by WangSansan</a>

看看結果

這裏寫圖片描述

好了,底部部分完成。

LOGO部分,不知道是圖片還是純文字,頁面上右鍵查看源代碼,或者直接把頁面另存到桌面

查看html,18行

<a class="brand" href="http://192.168.1.1/cgi-bin/luci/#">OpenWrt</a>

可以看到是文字Logo,如果是圖片或許還方便一些,直接把logo替換就行,既然是文字,那就找找在哪兒修改

頁面底部佈局的文件是 “view/themes/bootstrap/footer.htm”

修改完成後退出vim,查看同級目錄,包含一個文件 header.htm

vim打開,分析一下。就是這份文件。

162行和184行,修改一下,要加Logo也可以加一個Logo

<title><%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI</title>
...
...
...
<a class="brand" href="#"><%=boardinfo.hostname or "?"%></a>

修改後的代碼

<title>WangSansan - LuCI</title>
...
...
...
<a class="brand" href="#">WangSansan</a>

修改後大概這樣子

這裏寫圖片描述

0x05 Web界面功能添加與內容開發

本來想把web功能部分與靜態頁面修改放到一起寫,靜態頁面的修改,只研究了半個小時就能搞定了,本以爲加功能嘛,大概瀏覽了一下,無非就是一堆Lua代碼,增刪改也就一會兒的事,研究了才發現除了Lua代碼,還有目錄結構和包含關係,這部分相對於純靜態頁面的修改,還是稍有難度,所以單獨分節,好了,接着上面的步驟來說。

靜態內容的修改,沒什麼難度,既然我們是二次開發,那我們就嘗試增加點新功能。

先登陸進去

這裏寫圖片描述

常規的路由器功能,該有的都有。

接下來就可以開始定製屬於我們自己的路由器界面了。

不建議直接對原油配置文件的內容進行修改

我們先把LuCi的配置文件是怎麼工作的搞明白,在一步一步進行我們的二次開發工作。

LuCI採用了MVC三層架構,使用Lua腳本開發,在/usr/lib/lua/luci目錄下,分別對應、、三個文件夾,做開發的同學,對MVC架構應該就比較熟悉了,模型(model)-視圖(view)-控制器(controller),Luci採用的Lua進行開發,我們不需要定義自己的視圖框架的話基本不需要對view層進行修改,基本上只需要修改model層就可以完成我們功能的添加。

Luci運行時,會掃描controller目錄下的所有*.lua文件,進行功能入口的註冊並展示在Web頁面

當我們在Web頁面點擊各功能入口時,Luci會執行model目錄下的對應入口功能模型

1、簡單的CBI格式

2、註冊一個模塊入口

首先進入controller目錄,創建一個文件wangsansan.lua

寫入內容

module("luci.controller.wangsansan", package.seeall)

function index()
        entry({"admin", "wangsansan_url"},
                cbi("admin_wangsansan/test"),
                _("Test"))
end

訪問一下,可以看到我們已經添加了一個名爲“Test”的入口

並且點擊之後的url跳轉路徑是 http://192.168.1.1/cgi-bin/luci/admin/wangsansan_url

entry({"admin", "wangsansan_url"},cbi("admin_wangsansan/test"), _("Test"))

這條語句我折行了,看不懂的話,把它合併到一行來看就行了

第2個參數表示調用的路徑,就下面這行內容

cbi("admin_wangsansan/test")

cbi() 這個函數會檢索到model目錄下,那這一行就是說,目標文件路徑爲model/cbi/admin_wangsansan/test.lua

這裏寫圖片描述

不過這個時候我們點擊Test會報錯,因爲我們還沒有配置CBI模塊

3、配置對應入口的CBI模塊

首先創建配置文件

# echo "config wangsansan" > /etc/config/wangsansan

接下來配置CBI模塊,創建文件model/cbi/admin_wangsansan/test.lua

寫入下面的內容

local fs = require "nixio.fs"
local sys = require "luci.sys"

local m, s

m = Map("wangsansan", "wangsansan_title", "wangsansan_explain")
s = m:section(TypedSection, "wangsansan")
s.anonymous=true

return m

好了,點擊Test欄目,訪問一下

這裏寫圖片描述

好了,可以看到和我們配置的信息是一樣的。

自己純手動建立過一遍,就能弄明白怎麼回事,我們可以開始自己定製我們想要的界面了

提供參考連接:

LuCi API
https://htmlpreview.github.io/?https://raw.githubusercontent.com/openwrt/luci/master/documentation/api/index.html

Openwrt Luci界面開發http://blog.csdn.net/lichao_ustc/article/details/42739563

爲你的luci添加自助高級配置界面http://www.right.com.cn/forum/thread-183560-1-1.html

Openwrt開發與Luci介紹http://www.jianshu.com/p/bfb93c4e8dc9


折騰幾天的成果,可能有些坑爬出來之後,就忘了,如果大家有遇到其它坑,可以在博客下留言,如果恰好我懂,我會回覆。

CSDN博客:http://blog.csdn.net/byb123
個人博客:https://www.wangsansan.com
個人微信公衆號:iamwangsansan

歡迎關注公衆號


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章