標籤:linux shell openwrt coova chilli
跟大資料沒關係,只是幫朋友忙排了個錯記錄一下。
以前關係很不錯的同事,目前在企業級wifi領域創業,採購了我們的巨量資料服務,正在給他做平台的搭建和調試。然後這幾天他這個CEO在調試路由器的時候遇到一些問題,在搞大資料的同時捎帶手解決了一下他這個問題。
OpenWRT,嵌入式Linux,主要用在MIPS或ARM裝置上。路由器和wifi裝置很多會採用這個系統,特點是輕巧。
Coova-Chilli,在openwrt下的接入存取控制器,提供認證網關,可以使用radius或http來做接入計費等工作。
正常的話,在啟動chilli以後,會啟動四個tun虛擬隧道網卡,而故障是偶發性的,不週期性會有兩個IP地址一樣的tun裝置。比如是這樣
tun0 10.1.0.1
tun1 10.1.0.1
tun2 10.2.0.1
tun3 10.3.0.1
tun4 10.4.0.1
正常的情況下是應該只有tun0-3的裝置,但是每次啟動都會多出一兩個tun,而且還不固定,有時候是tun0-1 IP地址一樣,有時候tun2-3 IP地址一樣。而且OpenWRT預設是不記錄syslog的。很難排查。其實可以從logread裡面讀取syslog,但是syslog裡其實沒記錄任何東西。
那哥們以前也是寫代碼的,苦熬了三個通宵沒找到問題在哪,在chilli啟動指令碼裡面設定了各種記log,wait,sleep,都沒用。下午過去討論完當前大資料平台的需求就沒事了,然後我閑的蛋疼就給他看了一下那個指令碼,chilli指令碼應該沒有太多的問題,然後他是按照官方部署文檔搭建的。一開始也沒看出問題在哪。chilli指令碼預設是放在/etc/init.d目錄下的。按說不會有問題,後來快感來了,他告訴我他寫了一個命令在rc.local做啟動,我看了一下rc.local裡面,他寫了一個啟動指令碼放到了/root下面。vi 那個在/root下的啟動指令碼,裡面寫了一個/etc/init.d/chilli restart。我就問他這是幹嘛用的,他說wrt官方讓這樣寫,說這樣寫保險。我嘗試登出掉restart行,重啟10遍,tun隧道都毫無問題。20分鐘搞定。
問題分析
chilli原始指令碼如下
#! /bin/sh ### BEGIN INIT INFO # Provides: chilli # Required-Start: $remote_fs $syslog $network # Required-Stop: $remote_fs $syslog $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start CoovaChilli daemon at boot time # Description: Enable CoovaChilli service provided by daemon. ### END INIT INFO PATH=/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/chilli NAME=chilli DESC=chilli START_CHILLI=0 if [ -f /etc/default/chilli ] ; then . /etc/default/chilli fi if [ "$START_CHILLI" != "1" ] ; then echo "Chilli default off. Look at /etc/default/chilli" exit 0 fi test -f $DAEMON || exit 0 . /etc/chilli/functions MULTI=$(ls /etc/chilli/*/chilli.conf 2>/dev/null) [ -z "$DHCPIF" ] && [ -n "$MULTI" ] && { for c in $MULTI; do echo "Found configuration $c" DHCPIF=$(basename $(echo $c|sed ‘s#/chilli.conf##‘)) export DHCPIF echo "Running DHCPIF=$DHCPIF $0 $*" sh $0 $* done exit } if [ -n "$DHCPIF" ]; then CONFIG=/etc/chilli/$DHCPIF/chilli.conf else CONFIG=/etc/chilli.conf fi [ -f $CONFIG ] || { echo "$CONFIG Not found" exit 0 } check_required RETVAL=0 prog="chilli" case "$1" in start) echo -n "Starting $DESC: " /sbin/modprobe tun >/dev/null 2>&1 echo 1 > /proc/sys/net/ipv4/ip_forward writeconfig radiusconfig test ${HS_ADMINTERVAL:-0} -gt 0 && { (crontab -l 2>&- | grep -v $0 echo "*/$HS_ADMINTERVAL * * * * $0 radconfig" ) | crontab - 2>&- } ifconfig $HS_LANIF 0.0.0.0 start-stop-daemon --start --quiet --pidfile /var/run/$NAME.$HS_LANIF.pid \ --exec $DAEMON -- -c $CONFIG RETVAL=$? echo "$NAME." ;; checkrunning) check=`start-stop-daemon --start --exec $DAEMON --test` if [ x"$check" != x"$DAEMON already running." ] ; then $0 start fi ;; radconfig) [ -e $MAIN_CONF ] || writeconfig radiusconfig ;; restart) $0 stop sleep 1 $0 start RETVAL=$? ;; stop) echo -n "Stopping $DESC: " crontab -l 2>&- | grep -v $0 | crontab - start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/$NAME.$HS_LANIF.pid \ --exec $DAEMON echo "$NAME." ;; reload) echo "Reloading $DESC." start-stop-daemon --stop --signal 1 --quiet --pidfile \ /var/run/$NAME.$HS_LANIF.pid --exec $DAEMON ;; condrestart) check=`start-stop-daemon --start --exec $DAEMON --test` if [ x"$check" != x"$DAEMON already running." ] ; then $0 restart RETVAL=$? fi ;; status) status chilli RETVAL=$? ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|condrestart|status|reload|radconfig}" >&2 exit 1 ;; esac exit 0
問題在於,他在調試的時候,在for c in $MULTI迴圈裡面,為了保證每個子進程都啟動成功,加了一個wait,後面在建立tun通道的時候為了調試又加了幾個sleep。照著官方文檔,他又加了個restart到rc.local裡面,這樣問題就來了,/etc/init.d裡面是自動執行chilli start命令的,而加上了wait和sleep。init.d的啟動指令碼會等待,而這時候Linux在不同的tty又啟動了rc.local裡面的chilli restart命令,於是兩個或三個相同的tun IP地址就會共同存在。
反正問題解決了,鑒於他為這種破事熬了三個通宵,我就可以以Crowdsourced Security Testing的口吻教育這個親自偵錯工具的CEO:“盡信書不如無書”。開源系統的官方文檔往往滯後,可能新版本早就解決了需要restart的問題,但是文檔沒有及時更新,導致這種問題的發生。
總結,瞭解各種系統的工作原理是多麼重要。
最後,幫這哥們發個招聘廣告,他們表面上是個做wifi硬體的創業團隊,氣氛融洽,待遇優厚,其實是個氣氛融洽,待遇優厚的大資料公司。公司的核心重點是基於hadoop的大資料採礦和機器學習,歡迎網友自薦或推薦相關人才,不在於說你技術有多牛,就算剛從大學出來也沒問題,我這老闆朋友更看重你是否具備鑽研和學習的精神,加入該公司會得到本屌的Hadoop開發與營運技術的親身指導。機會難得,踴躍報名。
本文出自 “實踐檢驗真理” 部落格,轉載請與作者聯絡!
OpenWRT嵌入式Linux故障排除一例