busybox 的安裝
busybox-1.18.5.tar.bz2
make menuconfig # This creates a file called ".config"
make # This creates the "busybox" executable
make install # or make CONFIG_PREFIX=/path/from/root install
You will probably need to make your busybox binary setuid root to ensure all configured applets will work properly.
chmod 4755 ./_install/bin/busybox
***********************************************************************************/
httpd server Haserl
http://haserl.sourceforge.net/manpage.html
/***********************************************************************************/
使用選項
$ sudo ./busybox httpd -f // -f 前景模式,可以看打印 // -f == 非daemon()
httpd -p 8080 -h $HOME/public_html
httpd -u www
httpd -p 80 -u 80 -h $PWD -c /etc/httpd.conf -r "Web Server Authentication"
* foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World"
* bar=`httpd -e "<Hello World>"` # encode as "<Hello World>"
配置文件
服務器根目錄的設置 home_httpd * H:/serverroot # define the server root. It will override -h
特殊IP的訪問控制 deny > allow > deny * 拒絕後也是空白?HTTP 錯誤 403 - 禁止
* A:172.20. # Allow address from 172.20.0.0/16
* D:* # Deny from other IP connections
特殊頁面的設置 404不起作用?絕對路徑
* E404:/path/e404.html # /path/e404.html is the 404 (not found) error page
* I:index.html # Show index.html when a directory is requested
代理地址轉換 * P:/url:[http://]hostname[:port]/new/path
# When /urlXXXXXX is requested, reverse proxy it to
http://hostname[:port]/new/pathXXXXXX
目錄權限控制
* /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/
server: Http頭域中包含"WWW-Authenticate: Basic realm=\".\"\r\n" // 客戶端會彈出window鏈接到IP對話框要求輸入用戶名密碼
client: Authorization: Basic YWFhOmJiYg==\r\n // 輸入用戶名和密碼後,以加密形式送出
httpd 中的權限表: 是按照URL長度從大到小排列的!所以查找時按照最近匹配原則。
文件的執行程序
* .au:audio/basic # additional mime type for audio.au files
* *.php:/path/php # run xxx.php through an interpreter
HTTP協議:
GET:
在請求時將請求的內容添加到URL後,
http://192.168.60.129/cgi-bin/xmlPost?Text_Field=ding&Radio_Button=2&Submit=Submit
把問號後的全部記錄到環境變量 "QUERY_STRING"
POST:
http://192.168.60.129/cgi-bin/xmlPost
在請求的頭域中找內容長度"Content-length:" 記錄到環境變量"CONTENT_LENGTH",根據長度從標準輸入流中取得POST的內容
fgets(xmlData, dataLen + 1, stdin); // 最多隻能讀入n-1個字符。讀入結束後,系統將自動在最後加'\0',並以str作爲函數值返回
xmlData[]: Text_Field=ding&Radio_Button=2&Text_Area=lidan&Submit=Submit
// <input type=submit value=POST> 沒有name, 數據中就沒有這一項
請求有圖片的網頁:會發送2次請求
dld:handleIncoming enter(buf = GET /cgi-bin/getPageInfo?deviceInfo.html HTTP/1.1)...
dld:handleIncoming enter(buf = GET /cgiPic/cisco_Logo.gif HTTP/1.1)...
httpd.c 代碼流程
1. main():
if (daemon(1, 0) < 0) // nochdir = 0, 進入根目錄; noclose = 0, 不輸出任何打印!!!
運行成功後,父進程自殺;後續都是子進程的打印以及處理!!!
2. mini_httpd():
父進程循環等待客戶端的請求
子1進程將0,1重定向到與客戶端通信的socket
並處理請求 handle_incoming_and_exit
3. handle_incoming_and_exit // 分析GET行,解析頭域Auth..., 解析URL, 調用CGI或者File
send_cgi_and_exit // CGI的處理:
子2進程將0,1重定向到管道, // dup2(outFd, 1);
CGI程序從toCgi管道中讀,寫入fromCgi管道 // execv(realpath_buff, argp); 子進程執行CGI程序
父2進程=子1: 0, 1爲與客戶通信的socket
還有與子2進程通信的2個管道
4. cgi_io_loop_and_exit(與子進程通信的2個管道) // 父2進程處理
讀 從0(socket)來的數據, 父進程寫到toCgi[1]中 // 子進程從toCgi[0]中讀。通過以上子2進程0,1重定向實現!!!
讀 從fromCgi[0]中來的數據,父進程寫到1(socket)中。 // CGI生成的數據子進程寫到fromCgi[1]中。同上!!!
1. 還有客戶端的數據時,打開toCgi,準備寫入
2. 有需要接受post的數據時,從0讀,父寫到 toCgi
3. 否則關閉toCgi
4. 從 緩存hdr_ptr 寫到 toCgi
5. 從 0 讀,保存到緩存
6. 從 fromCgi 讀,保存到rbuf,然後寫到 1 // 可能加入頭域等東東
5. #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
a. 在分析請求的頭域中,如果含有 "Authorization:" , 則提取用戶名密碼進行驗證
驗證 check_user_passwd : 與配置文件httpd.conf 中的"/file:user:pass"字段 進行比較
b. 驗證失敗,則發送401 // send_headers_and_exit(HTTP_UNAUTHORIZED)
WWW-Authenticate: Basic realm="SEPC89C1DA3532B"\r\n // server response head中含有此字段,客戶端瀏覽器會彈出window窗口,要求輸入密碼
6. ME:開啓CUCM鑑權流程
ENABLE_FEATURE_HTTPD_BASIC_AUTH
ENABLE_AUTH_TO_CUCM
V:/CGI/Screenshot
7. ME: httpd.conf
U:/CGI/Screenshot:/cgi-bin/screenShot
V:/CGI/Screenshot
httpd.c Q&&A
0. 爲什麼handle_incoming_and_exit後的打印在控制檯跟蹤不到呢?
在 mini_httpd 函數中 // 即向0,1中讀寫的東西,實際都送到了套接字中了,因此後面的打印在控制檯屏幕顯示不出來,而在抓包工具中的包中!!!
n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
if (fork() == 0) {
/* child */
/* Do not reload config on HUP */
signal(SIGHUP, SIG_IGN);
close(server_socket);
xmove_fd(n, 0); // 把 0 標準輸入重定向到 打開的套接字,並關閉 n
xdup2(0, 1); // 把 1標準輸出重定向到 0.
handle_incoming_and_exit(&fromAddr);
}
0. ENABLE_FEATURE_HTTPD_BASIC_AUTH 默認是打開的,爲什麼訪問網頁時沒有要求輸入密碼?
客戶端沒有送密碼 且 配置文件也沒有配置 就默認爲通過驗證。
如何打開輸入密碼框: 在httpd.conf中加入 /cgi-bin:aaa:bbb,第一次無密碼驗證失敗後,要求輸入密碼
1. 錯誤505 不支持的版本 // http/1.1 not ,
2. busybox 中的 getLine() !!!注意好多全局的變量!!!
讀頭域到buf中,遇到/r/n變爲\0, 沒有處理完,繼續處理,直到讀的內容處理都處理完了,纔再讀
3. 配置文件無P:,爲什麼會走到ENABLE_FEATURE_HTTPD_PROXY 代理的處理中?
爲什麼send_cgi_and_exit 中的putenv setenv 有問題,走不下去? // 都是入參相關的變量
局部變量指針等在開頭賦值,中間處理到CUCM鑑權,socket通信後,
前面的指針的值莫名其秒的變了:指針不是空,printf後死掉,應該是超長 // strerror buflen=2147439428???
原因: char head_for_cucm_auth[] = {0}; // 竟然沒有大小,導致棧空間被踩了,!!!
另外局部數組 不要定義太大了。 // char * 8192
4. 爲什麼沒有-c時,會有錯誤打印 ?// httpd: config error 'U:/CGI/Execute:/cgi-bin/Execute' in 'httpd.conf'
沒有匹配任何一個分支,走到最後就會打印錯誤
沒有 -c, 也沒有etc中的,就取當前路徑下的httpd.conf 並且修改爲 TRY_CURDIR_PARSE ,就走不進 U P
5. 爲何配置P不起作用 // #if ENABLE_FEATURE_HTTPD_PROXY 默認打開的
if (flag == FIRST_PARSE && ch == 'P') { //busybox要求第一次/etc/httpd.config(or -c /tmp/test/httpd.conf)才解析配置文件的某些項,我改動時刪除了 flag 限制!!!
busybox 中P的鏈表是從最後一條在表頭,倒序,且比較時,按照url_from的長度匹配的方式。
(如果配置了P:/:/cgi-bin/getPageInfo, 導致 / /aaa 可能都匹配同一個) // 我改動爲完全匹配
只要配置"/", 代理重入時,就會再次匹配上,從而導致死循環,out of memory!
6. 爲什麼get可以,Post時,cucm Auth失敗,返回500?
因爲:收到的字段的順序是不固定的,取得Authorization: Basic ZGxkOmRsZA==\r\n 後的密碼要保存一份,以免被後續的覆蓋。
// gcc 編譯的,在虛擬機上跑的httpd, IP: 用橋接的
http://10.50.146.14:8080/cgi-bin/test-get?Text_Field=&Submit=Submit
7. httpd:bind: 地址已經被使用
80端口在虛擬機上被其他進程使用了,話機裏應該沒有使用它的。
netstat -an |grep :80
./busybox httpd -p 8080
8. 爲什麼執行test-get時,顯示的空白
cat -A test-get // 查看 多了回車 ^M
vi 中不可見的 :set ff=unix
vi裏面用一個命令(:%s/^m//g)刪除即可。
CGI
1. 在httpd 運行的目錄下建立目錄 cgi-bin and cgiPic,
cgi-bin中放入 可執行文件
cgiPic 中放入 圖片 或者 彈出頁面
// 可執行文件讀取某html文件,此文件中含有圖片或者彈出頁面, 其存放位置應該相對於 讀取他們的可執行文件,而不是包含他們的html文件
eg. <IMG SRC="../cgiPic/cisco_Logo.gif"
2. 網頁中的鏈接使用相對路徑
3. 根目錄: 默認的根目錄是httpd 運行的目錄
配置文件:H:/... > -h /usr/...
4. http response head 如果不完整的話,wireShark是跟蹤不到服務器迴應的包的!!!
6. 僅僅CGI程序的錯誤會導致“找不到伺服器或 DNS 錯誤”!!!
可能CGI程序掛掉了,webServer停在那裏,沒有給客戶端迴應。
7. 頭域的區分:每行後面有 /r/n ; 結尾有 /r/n /r/n , 後面是