瀏覽模式: 普通 | 列表

更換 ssh 服務程式的 Port

更換 ssh 服務程式的 Port

ssh 服務程式變更聆聽 Port 方式很簡單,通常修改主機的 /etc/ssh/sshd_config 檔案

配置設定 Port XXXX 然後執行 /etc/init.d/sshd restart 後

可以執行 netstat –nlp指令確認一下 sshd 是否有聆聽於 Port XXXX,有的話就表示該設定就生效了

標籤: Linux

將寄到yahoo的信由hinet去轉寄設定

1.將寄到yahoo的信由hinet去轉寄設定如下:

#vi /etc/postfix/transport

在最後加入

yahoo.com.tw smtp:[msa.hinet.net]

這裏告訴postfix 若是要寄到usrname@yahoo.com.tw請使用smtp協定將它轉往msa.hinet.net

#postmap /etc/postfix/transport 之後就會建立一個transport.db資料庫

在來就可以測試一下寄信到yahoo後,可以在maillog中查到一段log如下

to=, relay=msa.hinet.net[168.95.4.211], delay=10, status=sent (250 JAA12543 Message accepted for delivery)

標籤: Linux

postfix 文件

建置 POSTFIX 伺服器

作者:李忠憲 shane@mail.spps.tp.edu.tw

2003/12/09

增補第九章:2004/01/05

postfix 是除了 sendmail 以外 ,最被廣泛採用的 Linux 郵件伺服器,一般使用的觀感不外乎兩點:

一、安全:垃圾信過濾機制較聰明,就算什麼都沒設定,也能濾掉許多 sendmail 擋不到的信。

二、簡單:不需設定,伺服器就能正常運作。

雖然以上談的這兩點特色,到底是好是壞還有許多爭議,但 Postfix 對於郵件服務需求量不高的校園來說,可以說是一個很好的選擇!

本文是假設您已經讀過 Linux 進階班講義,因此對於 MUA、MTA、MDA、MSA 已經有概念,並且了解電子郵件結構及其欄位義涵,能自行設定啟用 IMAP 及 POP3 服務,並能利用 telnet 工具檢測伺服器情形,但對於 postfix 運作原理不甚清楚,想知道如何依自己的需要作各種過濾設定!那麼本文的內容應該對你很實用!

 

壹、從 sendmail 到 postfix

redhat 系統預設的郵件伺服器是 sendmail ,而 postfix 是不會自動安裝的,如果一開始安裝系統時忘記把 postfix 裝起來,請放入系統光碟第二片,依底下指令安裝:

mount /mnt/cdrom

cd /mnt/cdrom/RedHat/RPMS

rpm -Uvh postfix*

cd /

eject

為了便利於 sendmail 和 postfix 之間進行切換,系統提供一個工具可以自動幫我們作設定遷移,請放入系統光碟第三片,依底下指令安裝:

mount /mnt/cdrom

cd /mnt/cdrom/RedHat/RPMS

rpm -Uvh redhat-switch-mail*

cd /

eject

要進行郵件伺服器切換,請輸入 redhat-switch-mail 然後選擇您想要用的伺服器(sendmail 或是 postfix),雖然選好後系統會自動將伺服器關閉和啟動好,但我們依然可以使用底下指定來確定這件事(假設您選中的是 postfix):

service sendmail stop

service postfix start

這樣 postfix 應該就會開始提供服務了!什麼都不用設定就會跑了嗎?是的!

postfix 本身也可以當成指令來執行,例如:

postfix check    檢查設定檔是否正確,相關資料夾是否建立,檔案擁有人和存取權限是否正確

postfix start        啟動服務

postfix stop        停止服務

postfix abort        立刻中斷服務

postfix reload       重新載入設定檔

postfix flush        將佇列中的郵件全部寄出去

 

貳、postfix 工作流程

sendmail 與 postfix 最大的不同在於程式結構上,sendmail 以一支大程式來執行所有的工作,而 postfix 則改採模組化設計,這種設計的好處在於:程式碼容易維護、模組功能有彈性容易擴充。底下將針對組成 postfix 的每個模組,它們各是負責哪些工作,又如何與其它模組配合,作一個解說。

底下先說明收信流程:

圖例說明:橢圓代表模組程式,黃色框代表郵件佇列或資料夾,藍色框代表設定檔。大框線內的模組是由 master 模組來控制行程。

  • 當郵件由本機寄出時,系統執行 sendmail 程式,由於之前執行過 redhat-switch-mail 的關係,此時 sendmail 已經連結到 postfix 套件中的 postdrop 模組,postdrop 模組負責將郵件存放在 maildrop 資料夾中,等候 pickup 處理, pickup 模組會對郵件內容進行檢查以保護 postfix 系統不會受到異常郵件的攻擊(譬如利用欄位溢位來破解主機)。
     
  • 如果郵件是來自網路,postfix 套件中的 smtpd 將會接收郵件並進行郵件過濾,為了應付千變萬化的偽裝郵件, 我們可以透過修改 UCE 設定檔(例如:來自 sendmail 的 access 設定檔),設定黑名單(或透過 RBL 黑名單資料庫取得黑名單)、 DNS 反查驗證,甚至是使用正規表達式來作字串匹配檢查等方法,進行嚴格的過濾。
     
  • 郵件有時候是來自 postfix 本身的 bounce 模組,例如:當郵件無法遞送時,bounce 模組會自動產生訊息以便通知寄信人。

     

  • 郵件有時候也會由 LDA 產生,在上圖中用一道單獨存在的箭頭來表示(可以想像一下:該箭頭是連結到送信流程中的 local 模組)。這種情形包括:根據 alias 別名資料庫改寫過收信人的郵件,或是根據每個使用者的 .forward 檔案指定的轉信信箱修改過收信人欄位的郵件。
     
  • 除了上述因無法遞送郵件引發的問題會由 bounce or defer 模組產生通知郵件外,其它的錯誤產生時 postfix 也會自行產生通知郵件,例如:SMTP 通訊協定逾時,UCE 過濾規則衝突......等等,當然這種情形下只會通知 postmaster,在上圖中一樣用那一道單獨存在的箭頭來表示。
     
  • 以上五種情況產生的新郵件,最後都會由 cleanup 模組進行最後的處理。首先它會補足郵件中所缺少的欄位(例如來自 console 的信件將會缺省 From: 欄位),並根據完整郵件地址格式改寫寄信人欄位(例如:shane@localhost 改成 shane@mail.spps.tp.edu.tw),接著讀取 canonical(全名對應) 和 virtual(虛擬對應) 設定檔,根據該設定改寫收信人欄位,所有動作處理完畢後,郵件被放置在 incoming 資料夾中,接著就會通知 qmgr 模組有新郵件到了,由 qmgr 模組開始進行送信作業 。
     
  • 當 cleanup 模組進行郵件欄位改寫時,實際上是呼叫 rewrite 模組來處理,和 sendmail 不同的是,postfix 並未發展出一套複雜的巨集語言來進行 rewrite 作業,相反的是採用單純的查表法來解決, 這也是 postfix 被批評功能不如 sendmail 強大的原因。postfix 開發者似乎認為 sendmail 之所以漏洞百出,與 rewrite 巨集語言大而無當有直接相關(純屬猜測)。

底下說明寄信流程:

  • qmgr 模組是整個郵件伺服器的核心,它將視情形呼叫 local、smtp、pipe 等 agent 模組來進行寄信作業。local 模組就是 LDA ,它負責將信件分到使用者信箱。smtp agent 顧名思義是指 smtp client 程式,而非 smtpd ,它負責將信件透過 SMTP protocol 遞送到網路上的遠端郵件伺服器。pipe 則用來處理傳真或其它封閉式網路系統的特殊電子郵件通訊協定。

    當郵件出現遞送失敗的情形,qmgr 就會將郵件放在 deferred 佇列中,並呼叫 bounce 模組處理,以避免延遲其他郵件的遞送作業 。

    正在處理中的郵件會被放在 active 佇列中,該佇列僅存放少量郵件,因為若郵件過多的話將會耗用大量記憶體,來自 incoming 資料夾的郵件,會根據郵件到達的順序依序進入 active 佇列, 而 deferred 佇列的郵件,將會暫停四個小時後,重新排入 active 佇列。

    此外,qmgr 也會根據 relocated 設定檔來產生通知郵件,relocated 設定檔用來設定帳號或網域遷移的通知訊息,當 qmgr 發現某封郵件的收信人已經遷移,則會呼叫 bounce 模組處理 。
     

  • 在遞送郵件的過程中,qmgr 會呼叫 rewrite 模組解析收信人地址,通常 rewrite 模組只會區分該信件是要到達本機,還是需要 relay,當然我們也可以透過 transport 設定檔,來要求 rewrite 模組針對特定收信人地址遞送給特定主機(通常用來設定將 mail gateway 收到的郵件轉給下屬郵件伺服器)。
     
  • 當信件無法遞送時(收信人或收信主機不存在或無回應), qmgr 呼叫 bounce 模組處理。bounce 模組會將障礙情形以郵件型式遞交給 cleanup 模組進行收信作業,同時將原始郵件排入 deferred 佇列,等待延遲遞送。如果無法遞送的原因是通訊協定或設定檔錯誤造成的(這種情形應通知管理員,而非寄信人),則信件將直接由 qmgr 處理,並不會去呼叫 bounce 模組。
     
  • LDA 模組主要工作是將信件寫入使用者的信箱中,或是根據 alias 設定或 .forward 設定改寫收信人欄位,並遞交給 cleanup 模組進行收信作業,除了 postfix 預設的 local 模組外,其它在 sendmail 中經常使用的外掛 LDA,例如:procmail,也可以繼續使用,這是因為 postfix 的 local 模組是與 sendmail 完全相容的。

其它幕後常駐模組:

  • master:這個模組用來監督 postfix 所有模組,是否有依照 master.cf 中的設定執行,並會將超過上限的行程砍掉,以符合效能調校相關設定值。
     
  • flush:這個模組用來維護 incoming 郵件佇列的雜湊表,它將郵件依收信目的地分類,建立多個雜湊表,當用戶端送出 ETRN spps.tp.edu.tw 要求時,則可以將要給 spps.tp.edu.tw 的郵件(有些可能還在排隊)優先全部寄出。
     
  • showq:當執行 mailq 指令查詢郵件佇列時,就是由此模組提供資訊。
     
  • proxymap:用來讀取設定檔,並提供設定檔內容給其他模組,之所以這樣做是為了減少硬碟 I/O 存取。
     
  • spawn:用來呼叫執行外掛程式,透過這個機制我們可以執行非 postfix 提供的過濾程式,例如:病毒過濾。
     
  • pipe:這個模組用來將郵件佇列中的郵件資料結構,傳輸給外部程式處理。當 master 模組啟動外掛程式時,透過 pipe 當白手套就可以和外掛程式憑藉參數傳遞來溝通。
     

常用工具:

  • postalias:當我們執行 newalias 時,由於 redhat-switch-mail 的作用,其實是在執行 postalias,所以你也可以不用因此改變使用習慣喔!如果要透過這個指令建立 alias 雜湊表,指令格式比 newalias 稍微複雜一點:postalias hash:/etc/postfix/aliases,這道命令也可以用 postmap 代替,例如:postmap hash:/etc/postfix/aliases,其餘功能請參閱 postmap 的介紹
  • postcat:這是一個郵件 RFC 格式的剖析器,可以將原始郵件顯示成容易閱讀的格式,有點像用 outlook express 看到的郵件內容(假如在郵件上按右鍵查看原始內容,你可能就看不懂了),請指定要查看的檔名:postcat /var/spool/postfix/deferred/filename,由於檔名都是使用郵件編號,如果不知道要看的郵件是什麼檔名時,可以用下面的指令查詢!
  • postqueue:用來取代 mailq 指令,使用 -p 參數就可以將郵件依編號順序列出郵件標頭(寄信人、收信人和信件主旨),方便檢索查詢!-s 參數則是列出前面介紹過的 flush 雜湊表!
  • postsuper:這個命令用來操作佇列中的郵件,只有 root 身分才能執行。參數 -d 用來刪除郵件,-r 用來將郵件排到不同佇列裡(maildropincomingactivedeferred),-p 當伺服器(或 postfix 程式)當掉重開機後,用來救回工作到一半的郵件。
  • postconf:這是個功能強大的工具,除了可以用來顯示 main.cf 的詳細設定內容外(自動分類),也可以用來除錯,甚至還提供修改設定的介面,例如:postconf -e mynetworks=168.100.189.0/25,這個功能如果結合 script 程式來運作,就能做到透過網頁遠端管理設定擋。我們經常使用 -n 參數,來查看 postfix 設定檔擺放的位置!
  • postmap:用來取代 makemap 指令,並且與 makemap 完全相容,支援的檔案類型包括:btreedbmhash當用來建立資料庫檔案時,語法如後:postmap hash:/etc/postfix/access,這個工具也可以用來查詢資料庫檔案裡的內容,例如:postmap -q 172.16.2 hash:/etc/postfix/access,這會列出該行的規則,如要刪除可以使用:postmap -d 172.16.2 hash:/etc/postfix/access,透過這個方式能及時有效的管理,不用重新修改 access 文字檔,然後雜湊成資料庫,然後重新啟動 postfix 載入設定檔等等,作一連串動作!

 

叁、main.cf 基本設定

postfix 最被人稱道的地方在於設定檔的可讀性很高(當然是跟 sendmail 比),而在主要設定檔 main.cf 中,需要自行定義的東西並不多,而且這些參數就算不去定義,依照預設值也可以運作:

由本機寄出的郵件要使用哪個網域名稱

在 sendmail 中,這個功能稱為網域偽裝,也就是說可以和主機名稱不同,例如:本機名稱為 mail.spps.tp.edu.tw,而寄出的郵件其寄信人欄位則可以使用 spps.tp.edu.tw。(須配合 DNS MX 紀錄使用)

myorigin=spps.tp.edu.tw

不使用簡略名稱時,設定如下:

myorigin=mail.spps.tp.edu.tw

由於主機名稱與網域名稱會被反覆引用在不同設定值,為了簡化設定,通常是定義成變數:

myhostname = mail.spps.tp.edu.tw
mydomain = spps.tp.edu.tw

#myorigin=$mydomain
myorigin=$myhostname (省略時,視同此設定)

當然以上變數也可以省略不定義,這種情況下 postfix 將使用 gethostname( ) 函數取得系統設定。如果是將 myorigin 省略,則視同為設定 $myhostname。

另外,如果本機是某個網域的 mail gateway,也就是說網域內的所有郵件伺服器,都必須把它們的郵件送到本機來處理,這種情形可以使用 masquerade_domains 讓 postfix 自動缺省寄信人欄位中的郵件主機名稱,例如:

masquerade_domains = $mydomain

假設 $mydomain 是 spps.tp.edu.tw,則無論信件是來自 stu.spps.tp.edu.tw 或 mail.spps.tp.edu.tw 都將會被改寫成 spps.tp.edu.tw。

如果你有某些帳號不想要讓 mail gateway 改寫寄信人欄位,可以設定底下的參數(預設不啟用):

masquerade_exceptions = root

啟用 masquerade_domains 功能只會改寫郵件標頭與信封裡的寄信人欄位,如果想要將收信人欄位一併改寫,可以設置底下的參數:

masquerade_classes = envelope_sender, envelope_recipient, header_sender, header_recipient

注意:這樣做將使得 mail gateway 無法寄信給下屬郵件伺服器,因為收信人欄位 @ 後面的郵件網域名稱會被改寫成 mail gateway 自己。

要接收來自哪些網路介面的郵件

底下參數是用來定義要處理來自哪些網路介面的郵件,當未定義時,預設會處理本機所有網卡(可以使用 ifconfig 觀察),如果定義成 localhost ,則只有 loopback 介面會接受郵件,也就是說只接受主控台或 WEB 介面寄出的郵件,不接受 MUA(outlook express)遞交的郵件:

inet_interfaces = localhost

設定成 all ,表示接受所有網路介面的郵件,這是預設值:

#inet_interfaces = all

設定成 $myhostname ,表示要透過 DNS 反查 IP,當本機 IP 是由 DHCP 指派,而 DNS 又未被設定成 DDNS ,將會出現不可預期的錯誤!

#inet_interfaces = $myhostname

底下範例將會在有 DNS A 紀錄的 IP 以及 loopback 介面上提供服務,在這裡我們可以發現 main.cf 中有許多設定可以設定超過一個值,將它們用逗號區隔開來就行了!(底下的設定範例不適用於 postfix 本身兼 Proxy/NAT 的場合)

#inet_interfaces = $myhostname, localhost

哪些網域的郵件是給本機的

定義在這裡的網域將被視為是 local 網域,換句話說寄到這些網域的郵件,會被接收並分信給本機使用者,相當於 sendmail 中的 local-host-name,當不使用 DNS MX 紀錄時,設定如下:

mydestination = $myhostname localhost.$mydomain

如果有使用 DNS MX 紀錄,需修改為:

mydestination = $myhostname localhost.$mydomain $mydomian

假設該伺服器在 DNS 上有多筆 A 或 CNAME 紀錄,則須將這些紀錄也寫上去,例如:

mydestination = $myhostname localhost.$mydomain $mydomian www.$mydomain ftp.$mydomain

哪些郵件要進行 relay

在 postfix 中針對轉信網域作處理的參數有兩個,一是用來定義區域網路網段的 mynetworks,另一個是 relay_domains,未被定義在這些參數裡的網域,系統將拒絕轉信!

首先說明區域網路網段設定,相關參數共有兩個:mynetworks_style 和 mynetworks,前者用來宣告區域網路類型,subnet 代表是子網路,這也是預設值,當未作設定時,postfix 將會自行根據 ifconfig 上登記的 IP 和 網路遮罩作運算,自動求出子網路的範圍;如果設定成 class,則是不理會遮罩,自動信任同一個 class 等級的電腦,如果該伺服器使用撥接上網,這樣設定將使得同一家 ISP 的撥接用戶,都可以利用本伺服器轉信,這是非常危險的(除非你是 ISP 公司);設定成 host 則僅該單機可以寄信。

#mynetworks_style = class
#mynetworks_style = subnet
#mynetworks_style = host

mynetworks 用來設定區域網路的 IP 範圍,剛才設定的 mynetworks_style 將會被此參數取代,如果省略不設定,則由 mynetworks_style 來決定要 binding 的網卡:

mynetworks = 168.100.189.0/25

mynetworks = 168.100.189.10

除了上面範例,設定成網段或單機外,也可以指定多個網段(多重 NAT 網域時),或是使用設定檔(條列式),或使用雜湊表(makemap hash postmap hash:)。

#mynetworks = 168.100.189.0/28, 127.0.0.0/8
#mynetworks = $config_directory/mynetworks
#mynetworks = hash:/etc/postfix/network_table

有關轉信網域設定,以上兩個參數就已經足以應付各種需求,但為了與 sendmail 相容,仍然保留 relay_domains 設定,與 sendmail 不同的是,如果該 relay_domain 在 DNS 上有定義 MX 紀錄,將會被 postfix 故意忽略,而當成 mynetworks 來處理,這是為了避免被利用作為廣告信回信站台;relay domain 對 sendmail 而言是雙向的,但對 postfix 而言則是單向的,只能寄信,而且不代收回信,因此如果要將本機設定成 mail gateway,請使用 mydestination,而不要使用 relay_domains(注意:很多介紹 postfix 的文章都犯此錯誤!)建議不要設置此參數,使用預設值「不啟用」。

#relay_domains = $mydestination

當本機為某台 mail gateway 的下屬伺服器時,必須要將所有寄出的信件交給 mail gateway 代轉,這時可以設定 relayhost 為該 mail gateway 的 IP。預設不啟用。

#relayhost = $mydomain
#relayhost = mg.spps.tp.edu.tw
#relayhost = [172.16.1.7]

哪些情況須通知管理員

所謂管理員是指 postmaster 信箱,請修改 alias 設定將 postmaster 對應成管理人員真正使用的信箱,以免警告郵件沒人理會堆積在伺服器上。

notify_classes 參數用來決定哪些情形下須通知管理員,預設值如下:

notify_classes = resource, software

可以使用的參數包含:

                                                                                                                                                                                                   
bounce當一般郵件無法交遞時,產生警告信給管理員(會附上原始郵件的內文)。注意:郵件無法交遞時,本來就會寄警告信給發信人,管理員收到的不過是複製版本。
2bounce當寄給發信人的警告信無法交遞時, 產生警告信給管理員。
delay當對方站台忙碌要求延遲遞送時,產生警告信給管理員(不會附上原始郵件)。
policy對方寄信的要求因為不符合安全規範已經被回絕(被規則過濾掉),此時會產生警告信給管理員。
protocol通訊協定錯誤時產生警告信通知管理員,我們比較感興趣的是對方使用了哪些不合法的 SMTP 命令。
resource系統資源短缺導致信件無法寄出,例如:硬碟 I/O 錯誤,此時會產生警告信給管理員。
software軟體安裝不全或程式錯誤造成的問題,產生警告信給管理員。

 Proxy/NAT 地址

當郵件伺服器位於 proxy 或 NAT 防火牆的後方時,此參數用來設定真實 IP,以避免因為 MX 紀錄與本機 IP 不同,將該信誤判成需 relay 到其它 MX 的郵件;當本機所查詢的 DNS 其回覆 MX 紀錄為虛擬 IP 時,此種現象將不會發生,因此在 NAT 虛擬網域中,架設內部專用 DNS 是非常重要的,請參考網路名稱系統一文的解說。預設值為:

proxy_interfaces =

當本機被設定成其它網域的備份 MX 時,如果未設置此參數,郵件會成為伺服器間互踢的皮球(去詢問其它網域的 DNS 查詢 MX 紀錄時,查到的必然是真實 IP,即使有架設內部專用 DNS 也沒用)。設定如下:

proxy_interfaces = 163.21.166.7

 

肆、main.cf UCE(unsolicited commercial email)過濾

過去這類的郵件被稱為垃圾郵件,比較正式的稱呼是 SPAM 郵件,postfix 則稱此種郵件為 UCE,有那麼一點縮小打擊範圍的含意,因此使用 UCE 過濾並無法解決其它問題郵件(例如:匿跡郵件、病毒郵件、郵件炸彈)所帶來的困擾,請不要期望過高。

儘管如此,與 sendmail 使用 access 來進行存取控管相比較,postfix 的 UCE 過濾顯然要精細得多,彈性也比較好,以外掛方式讀取過濾規則使得管理員能隨時修改設定,並將它模組化,可以說是 postfix 最大的優點。

如前所述,postfix 並不使用複雜的巨集語言來進行規則運算,而是採用較為單純的查表法來控制,但各位可不要小看它,它所支援的查表方式可謂琳瑯滿目,諸如:欄位比對( 純文字檔,欄位以逗號或空格或定位點區隔)、DBM 檢索、HASH 雜湊、NIS 查詢、RBL 查詢.....等,比對規則也可以選擇採用正規表示法(regexp)或是 perl 改良過的正規表示法(pcre)。

郵件標頭過濾

標頭過濾所過濾的對象,除了郵件標頭外,更擴大範圍到附加檔案的 MIME 標頭,使得過濾可以更精確的進行,而不會因規則過於模糊,殃及無辜的郵件。用過 procmail 的使用者要特別注意:附加檔案檔名或檔案類型是在此過濾,而非在郵件內文過濾。設定方式如下:

header_checks = regexp:/etc/postfix/header_checks
header_checks = pcre:/etc/postfix/header_checks

在外掛設定檔 header_checks(可以改用其它檔名)中,當字串比對命中時,可以採取各種處理動作,包括:

                                                                                                                                                                                                   
REJECT拒收信件。
OK跳過符合條件的標頭不作後續檢查,在 sendmail 中一旦 OK 該信件就會被接受,但在 postfix 中,OK 僅用來跳過該標頭的後續比對,萬一有其它標頭被拒絕,該封郵件一樣會被拒絕。
IGNORE從郵件刪除該標頭。
WARN附加警告訊息。
HOLD放回佇列,等候處理。
DISCARD直接將郵件丟棄,不回應拒收訊息。
FILTER transport.nexthop呼叫外掛過濾程式,進行郵件內文剖析過濾。外掛過濾程式可以是任何一種可執行的檔案,例如:shell script。該程式必須先定義在 master.cf 中,模擬成一個 socket 來執行(由 master 模組負責伺服監聽),當需要呼叫它執行時,postfix 中的 clearup 模組會將整封郵件丟到指定的 port 號,master 模組監聽到訊息後會執行相對應的過濾程式。

header_checks 的範例如下:

/^Subject: Make Money Fast/ REJECT
/^To: friend@public.com/ REJECT

如果未設置此參數,則郵件標頭過濾功能將會關閉不啟用,這是系統預設值。

郵件內文過濾

這是用來過濾所有標頭過濾沒檢查到的郵件內容,設定方式與前面相同:

body_checks = regexp:/etc/postfix/body_checks
body_checks = pcre:/etc/postfix/body_checks

如果未設置此參數,則郵件標頭過濾功能將會關閉不啟用,這是系統預設值。

用戶端過濾

當用戶使用 SMTP 通訊協定連上伺服器提出寄信請求時,針對用戶端輸入的指令進行過濾。在 Linux 系管師進階班講義 中已經詳細論及在 SMTP 連線階段中出現的各種欺騙伺服器的手法, postfix 提供非常詳盡的設定可以針對這些問題加以預防。使用用戶端過濾時,必須將 smtpd_delay_reject = yes 設定上去,這是系統預設值。當設定成 no 時,雖然效率較高,但是這樣做將會使得 HELO 網域偽裝、送信人信箱偽裝、寄信人信箱偽裝以外的其它過濾功能失效。

用戶端過濾能夠使用的過濾功能,包括:

                                                                                                                                                                                                                                                                                       
reject_unknown_client用戶端之 IP 或 Domain name 無法從 DNS 查詢驗證時,拒絕連線。
permit_mynetworks符合 $mynetworks 定義的用戶端允許連線。
reject_rbl_client從 SPAM 資料庫站台驗證用戶端網域名稱,符合時拒絕連線,當這種情況發生時,postfix 將會依照 default_rbl_reply 的設定回覆相關訊息,也可以依照 rbl_reply_maps 的設定根據不同用戶端給予不同訊息,事實上我們根本不需要設置此兩個參數(除非想將訊息改成中文)。這個參數必須放在最後面,當成過濾政策。
reject_rhsbl_client同上,使用另一種 SPAM 資料庫站台。這個參數必須放在最後面,當成過濾政策。
check_client_access根據 access 設定過濾存取權限,與 sendmail 中的 access 資料庫相容。 可以省略參數名稱,直接寫檔名,例如:hash:/etc/postfix/access。
permit允許連線,設定在過濾規則的最後面,表示未被之前的規則拒絕的用戶端一律允許連線,也就是採用黑名單政策。
defer延遲連線,設定在過濾規則的最後面,表示未被之前的規則拒絕或接受的用戶端,必須在稍後重新接受檢驗,也就是採用拖延政策。
reject拒絕連線,設定在過濾規則的最後面,表示未被之前的規則接受的用戶端一律拒絕連線,也就是採用白名單政策。
warn_if_reject被拒絕時產生警告訊息,這是用來測試過濾規則用的。
reject_unauth_pipelining當用戶端持續一直傳送 SMTP 命令時,拒絕其連線,這可以防止某些軟體一次寄送大量郵件。

使用用戶端過濾跟稍後會介紹的各種 SMTP 過濾,可以把規則依照前後順序編排成一組規則鍊(寫成一行,中間用逗號隔開或從逗號後面分行),由於組合出來的過濾功能並非單獨運作的,因此順序非常重要!

smtpd_client_restrictions = reject_rbl_client dialup.ecenter.idv.tw(台灣免費的 SPAM 資料庫:擋撥接發廣告信)

smtpd_client_restrictions = reject_rbl_client relays.ordb.org(國外免費的 SPAM 資料庫:擋開放轉信的伺服器)

smtpd_client_restrictions = reject_rbl_client spam.ecenter.idv.tw(台灣免費的 SPAM 資料庫:擋寄廣告信的信箱)

smtpd_client_restrictions = hash:/etc/postfix/access, reject(採用白名單政策)

smtpd_client_restrictions = permit_mynetworks,reject_unknown_client

smtpd_client_restrictions = permit_mynetworks,hash:/etc/postfix/client_checks,reject_unknown_client,reject_unauth_pipelining

取得石牌國小垃圾信阻擋清單(每日更新)

是否要求使用 HELO 命令

當啟用此功能時,將要求用戶端進行連線時須先傳送 HELO 字串,稍後我們可以根據 HELO 字串傳回來的網域名稱進行過濾,由於某些寄信程式不會傳送 HELO 命令,這樣做有可能會使得這些用戶端程式無法正常寄信。預設值是:

smtpd_helo_required = no

HELO 命令過濾

用來過濾 HELO 命令後面的網域名稱是否允許其連線,能夠使用的過濾功能,包括:

                                                                                                                                  
reject_invalid_hostname網域名稱字串不符合文法時,拒絕其連線。
reject_unknown_hostname網域名稱無法從 DNS 查到 A 或 MX 紀錄時,拒絕其連線。
reject_non_fqdn_hostname網域名稱不是完整 FQDN 格式時,拒絕其連線。
check_helo_access根據 access 設定過濾存取權限。
其它 permit、defer、reject、warn_if_reject、reject_unauth_pipelining 請參考前面的說明。

設定範例:

smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname

信封標頭欄位過濾

此功能用來過濾郵件的信封標頭是否符合 RFC 821 之規定,預設是不啟用此過濾。因為目前最多人使用的 MUA 是 outlook express,它會使用許多額外的標頭來進行郵件控制,例如:大家熟知的要求回覆功能,如果啟用此參數將使得這些信件被拒絕無法寄出。

strict_rfc821_envelopes = yes

寄信人過濾

此功能並非過濾郵件標頭裡的寄信人欄位,而是過濾 mail from: 命令後面的字串,預設值是不過濾,但由於廣告信寄信程式為了能順利寄信,經常會偽造此字串,建議應該啟用。

可以使用的選項包括:

                                                                                                                                                              
reject_unknown_sender_domain寄信人的網域名稱無法從 DNS 查詢驗證時,拒絕連線。
reject_rhsbl_sender寄信人信箱如果被紀錄在 SPAM 資料庫站台,就拒絕他連線。
check_sender_access根據 access 設定過濾存取權限。
reject_non_fqdn_sender寄信人的網域名稱不是完整 FQDN 格式時,拒絕其連線。
reject_sender_login_mismatch寄信人信箱與登入的帳號不吻合時,拒絕其連線。須配合 SASL 使用者認證機制使用(SMTP AUTH)。

配合 smtpd_sender_login_maps 指定的對應表,可以讓登入帳號與使用的信箱作對應,例如:shane 帳號可以用 webmaster 信箱寄信。

其它 permit、defer、reject、warn_if_reject、reject_unauth_pipelining 請參考前面的說明。

設定範例如下:

smtpd_sender_restrictions = reject_rhsbl_sender dsn.rfc-ignorant.org(國外免費的 SPAM 資料庫:擋寄廣告信的信箱)

smtpd_sender_restrictions = hash:/etc/postfix/access, reject_unknown_sender_domain

smtpd_sender_restrictions = permit_sasl_authenticated,reject_unknown_sender_domain,reject_non_fqdn_sender

收信人過濾

此功能並非過濾郵件標頭裡的收信人欄位,而是過濾 rcpt to: 命令後面的字串,預設值是不過濾,但由於廣告信寄信程式為了能順利寄信,經常會偽造此字串,建議應該啟用。

可以使用的選項包括:

                                                                                                                                                                                                                                                                              
permit_auth_destination收信人網域符合 $relay_domains、$mydestination、$inet_interfaces、$vitual_alias_domains、$virtual_mailbox_domains 的定義時,接受連線。
reject_unauth_destination收信人網域不符合上述設定時,拒絕連線。
permit_mx_backup當從 DNS 上查到本機為收信人網域的備份 MX 時,接受連線。使用此功能有安全漏洞,可以配合 permit_mx_backup_networks = 172.16.0.0/16 來檢查主要 MX 是否在該網段內,來加強過濾功能(避免被不信任的網域設定為轉信 MX)。
check_relay_domains允許代收要給 relay_domians 的信件。
check_recipient_access根據 access 設定過濾存取權限。
check_recipient_maps

當收信人網域不符合 permit_auth_destination 之要求,或是收信人信箱不符合 $local_recipient_maps、$virtual_alias_maps、$virtual_mailbox_maps、$relay_recipient_maps 的定義時,拒絕連線。此參數可以放在收信人過濾規則的最後面,當作過濾政策。

reject_unknown_recipient_domain收信人的網域名稱無法從 DNS 查詢驗證時,拒絕連線。
reject_rhsbl_recipient收信人信箱如果被紀錄在 SPAM 資料庫站台,就拒絕他連線。
reject_non_fqdn_recipient收信人的網域名稱不是完整 FQDN 格式時,拒絕其連線。
其它 permit、defer、reject、warn_if_reject、reject_unauth_pipelining 請參考前面的說明。

設定範例如下:

smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination,reject_non_fqdn_recipient

ETRN 命令過濾

用來過濾哪些網域或哪些用戶端,可以使用 ETRN 命令。ETRN 命令用來一次處理大量郵件,當某個用戶端使用 ETRN 時,有時候會影響到其它用戶寄信的效能,通常只有撥接用戶、幫撥接用戶轉信的 mail gateway、郵件討論群組(mailing list)或電子報發行站台,需要使用此功能。postfix 的預設值是所有用戶端都可以使用 ETRN 命令。

能使用的特殊參數只有 check_etrn_access,其餘與用戶端過濾參數相同,請自行查閱前文。設定範例如下:

smtpd_etrn_restrictions = permit_mynetworks, hash:/etc/postfix/etrn_access, reject

 

伍、效能調校

在這一章中,所有未特別說明的參數,都是設定在 main.cf 中!

行程限制

系統預設行程限制(default_process_limit)為 100,也就是說同時可以收發總共 100 封郵件,如果發現伺服器效能很差,可以嘗試降低此數值,請修改 master.cf:

# ==========================================================================
# service type private unpriv  chroot wakeup maxproc command + args
#                  (yes)    (yes)    (yes)    (never)  (100)
# ==========================================================================
    . . .
    smtp      inet      n           -               -               -               10               smtpd
    . . .

以上各欄位意義說明如下:

                                                                                                                                                                                                                               
service識別名稱
type服務類型總共有三種:inet、unix、fifo。inet 是指透過網路介面 sockets 提供服務(例如:127.0.0.1:25),unix 指使用 unix sockets 提供服務(直接呼叫執行),fifo 是指使用 pipe name 提供服務(例如:網路傳真) 。
private切斷對外服務,預設值是 yes。注意:inet 類型無法設定成 yes。
unpriv不要以 root 身分執行,而是以 $mail_owner 身分執行。預設值是 yes。
chroot開啟郵件暫存資料夾時,要不要將該資料夾變成根目錄,這是為了防止與 postfix 無關的資料夾遭到入侵者以 $mail_owner 身分闖入。預設值是 yes。注意:pipe、virtual 和 local 模組無法設定成 yes。
wakeup服務每隔多久喚醒一次,預設值是 0(不喚醒)。只有 pickup、qmgr 和 flush 模組需要設定喚醒週期。
maxproc最大執行緒。
command + args該服務執行的命令及參數。

master.cf 除了控制 postfix 各個模組的運作方式外,也可以加入外掛過濾引擎,postfix 希望透過這個方式與其它程式設計專家合作,後文將介紹兩個經常使用的過濾程式 SapmAssassin 以及病毒過濾軟體 amavisd + clamav。更詳細的內容可以自行到 www.postfix.org 查看或閱讀 /usr/share/doc/postfix-1.xx/README_FILES/FILTER_README!

同步處理限制

postfix 採用同步處理限制來進行流量調整和控制,當 postfix 寄信到某個郵件主機時,首先傳兩封信過去(initial_destination_concurrency = 2),如果一切正常則逐步增加每次傳送的量,一直到傳輸失敗或者是到達同步上限每次 20 封信(default_destination_concurrency_limit = 20)。

如果想要針對不同 agent 來設定同步上限,也可以使用底下的參數(未設定的參數將會沿用 default_destination_concurrency_limit 限制):

local_destination_concurrency_limit = 2
uucp_destination_concurrency_limit = 2
smtp_destination_concurrency_limit = 10

收信人限制

這是指一封信可以寄給多少人,postfix 預設可以處理 50 個收信人(default_destination_recipient_limit = 50),如果一封信的收信人超過 50 人,postfix 會自動將此信複製成很多份,以 50 人為單位分批寄送。

和同步處理限制一樣,可以針對不同 agent 來設定不同上限:

uucp_destination_recipient_limit = 2
smtp_destination_recipient_limit = 10

延遲傳送

當郵件伺服器使用撥接線路連線時,由於部分時段處於斷線狀態,當 postfix 處理信件時會因為無法收發信件,持續產生錯誤訊息,為了避免發生這個現象,我們可以設定 defer_transports = smtp 來告知 postfix,要從 smtp agent 傳送出去的郵件暫時不要傳送。這些郵件可以等到上線後,再以 ETRN 指令全部寄出。

如果本機是前述郵件伺服器的 mail gateway,由於該伺服器只有部分時段上線,因此有可能 mail gateway 已經累積許多信件等待傳送給它,為了避免 mail gateway 持續嘗試傳送,可以設定:

defer_transport = hold

接著在 /etc/postfix/transport 設定:

customer.com   hold:[gateway.customer.com]

這個設定的意思是,要給 customer.com 的郵件先暫存在 gateway.customer.com,等待前者上線後再全部傳送給它(使用 ETRN 命令)。

設定好後,還需修改 master.cf,找到 smtp 行程設定(可參考前面小節),將 smtp 改為 hold 即可:

hold   unix   -   -   n   -   -   smtp

傳送失敗處理

當郵件傳送失敗的時候,負責傳送郵件的 Agent 會將郵件退回給 qmgr 模組,qmgr 模組則會計算從郵件到達到現在的時間間隔,依此時間間隔將郵件排入延遲傳送佇列中,以等待下次傳送。

如果該封郵件傳送到一半的時候失敗了,也就是說有些收信人有收到,有些沒有。這種情況下,除了將該郵件排入延遲傳送佇列外,也會將傳送失敗的對象排入 dead 清單一段時間,在這段時間內如果有其它郵件要傳送給這些對象時,就會直接排入延遲傳送佇列,而不用徒勞無功地去嘗試傳送!

底下是有關於郵件傳送失敗處理的相關效能設定:

                                                                                                                                           
queue_run_delay = 1000sqmgr 模組每 1000 秒(約 16 分鐘)檢查一次 defer 佇列,查看是否有郵件須排入 active 佇列
maximal_queue_lifetime = 5d無法傳送的信件在 defer 佇列裡最多保存 5 天,超過時間則退給寄信人
minimal_backoff_time = 1000s傳送失敗的郵件至少在 defer 佇列中暫停 1000 秒,而且被排入 dead 清單的收信人至少也要待 1000 秒,也就是說在這段時間內不再嘗試寄信給他
maximal_backoff_time = 4000s傳送失敗的郵件最多在 defer 佇列中等待 4000 秒(約 1 小時)
qmgr_message_recipient_limit = 1000dead 清單的大小,也就是說第 1001 個傳送失敗的對象,不會被排入 dead 清單

拖延戰術

當懷有惡意的用戶端連續傳送大量郵件時,postfix 為了處理這些郵件耗掉太多資源,導致無法正常工作,這也就是經常被討論的「阻斷服務攻擊」。

postfix 的設計者認為阻斷服務攻擊是不可能被解決的,因為我們無法單從郵件區分出它是惡意或善意,但是我們可以透過一些手段來降低損害。postfix 採用的方法是針對每條連線,設定一個連線錯誤計數器( session error count),當用戶端連線時,開啟計數器,如果用戶端傳送不存在的 SMTP 命令(這絕對是惡意想阻斷服務),或是超過字數限制的長字串(記憶體溢位攻擊)、超過一行的標頭(引發郵件剖析錯誤),計數器就會不斷累加。當郵件交寄成功時,計數器才會歸零重新計算。

現在我們只要根據計數器採取適當的處理動作就行了:

                                                                                   
smtpd_soft_error_limit = 10當計數器到達 10 時,就暫停該連線一段時間
smtpd_hard_error_limit = 100當計數器到達 100 時,直接斷線
smtpd_error_sleep_time = 5s每次暫停 5 秒鐘

 

陸、資源管制

postfix 可以在記憶體有限的系統上執行,而不會影響其它服務的效能,這是因為 postfix 提供的記憶體管理功能非常有彈性,可以依據各種需求加以調整。

每封郵件用量限制

當 postfix 處理郵件時,必須將郵件暫存於郵件佇列中,其中 maildrop 和 incoming 佇列使用硬碟,而 active 和 deferred 則使用記憶體,每封暫存在佇列中的郵件耗用多少記憶體是由郵件資料結構來決定,幸運的是這個資料結構的欄位大小是可以微調的,透過這些微調就能決定 postfix 的最大記憶體用量了!

                                                                                                                                                                       
line_length_limit = 2048從用戶端接收待寄郵件時,每行最多 2 KB
header_size_limit = 102400每封郵件的標頭大小不得超過 100 KB
extract_recipient_limit = 10240每封郵件的收信人欄位不得超過 10 KB
message_size_limit = 10240000每封郵件(包含信封)的大小,不得超過 10 MB
queue_minfree =當記憶體剩下多少 Bytes 時,才可以處理下一封郵件,預設是沒有限制。
bounce_size_limit = 50000警告信的大小限制為 50 KB。

假設通通使用預設值,也就是所有參數都不設置,那麼處理一封郵件須耗用 10.05 MB,再加上 postfix 模組程式的大小,總共約 20 MB,這也就是 postfix 運行的最小需求了!

郵件數量限制

當前述用量限制設置完畢後,接著我們還可以針對郵件佇列一次要處理多少郵件作出限制,把每封郵件記憶體用量乘上郵件數量,就可以算出所需的記憶體總量,當記憶體足夠時,我們當然希望儘可能多處理幾封郵件來增進 postfix 的效能。

                                                                                   
qmgr_message_recipient_limit = 1000這個參數之前介紹過了,除了用來控制 dead 清單的大小外,也控制著處理中的郵件收信人總量,兩者的預設限制都是 1000。
qmgr_message_active_limit = 1000最多同時處理 1000 封郵件。
duplicate_filter_limit = 1000在進行收信人過濾時,要快取多少已通過過濾的清單,這個功能是用來提高過濾效能,預設要快取 1000 個不同收信人

時間限制

postfix 某些模組在運作時,會依照設定檔的要求讀取外掛程式或是執行 shell 命令,有些則是會讀取外部檔案。如果無限制的讓 postfix 等待外部命令執行完畢或等待外部檔案讀取完畢,將會因為這些外部程式的設計不當或 I/O 衝突,而導致 postfix 無法運作,因此就需要設定等候時間限制,超過此時間限制 postfix 將逕行處理下一個程序。

舉例來說:當 local agent 將郵件分到使用者信箱時,會透過 proxymap 模組讀取 alias 資料庫,接著根據 alias 設定讀取 :include: 檔案,最後讀取 .forward 檔案,前述動作中如果其中一個因為系統 I/O 忙碌無法於時間限制內讀取檔案,local agent 就會直接跳過進行下一個處理動作。

                                                       
command_time_limit = 1000s等候外部命令或 I/O 的時間不可超過 16 分鐘。
service_time_limit =這個參數的目的是允許不同 service 採用不同時間限制,因此它會取代前述參數的設定,其中 service 就是 master.cf 中的第一個欄位。

檔案鎖定

當 local agent 要將信件分到使用者信箱時,有時候使用者正透過 POP3 讀取信箱,因此信箱被鎖定無法開啟,這種情況發生時,local agent 必須等候一段時間重新嘗試讀取檔案,但也不能一直等下去,所以必須要有一些限制。

postfix 支援兩種的檔案鎖定機制:一、使用系統函式 fcntl( ) 或 flock( ),二、使用 local file,postfix 將根據作業系統的不同,選擇其中一種或兩種並用。有關檔案鎖定機制在這裡不予討論,有興趣的讀者可以從「專業 Linux 程式設計」(Wrox 出版,碁峯翻譯經銷)一書一窺究竟。

                                                                                   
deliver_lock_attempts = 5檔案被鎖定時,嘗試讀取 5 次。
deliver_lock_delay = 1s每次嘗試讀取前,先等候一秒鐘。
stale_lock_time = 500當 lock file 存在超過 500s 時,強制刪除 lock file 解除其鎖定狀態。使用 lock file 其實是透過程式設計技巧來模擬檔案鎖定功能,它必須由程式設計師自行維護鎖定狀態,萬一有粗心的設計者鎖定檔案後忘記解除,或是程式當掉無法解除鎖定,都會造成檔案長期被鎖定的假象,所以需要此設定來排除問題。

行程自動回復

當行程或子執行緒因為某些原因當掉,例如:記憶體不足......等,這個時候 master 將會延遲一段時間後嘗試重新啟動該行程。當然,如果程式當掉的原因是 main.cf 檔案損毀所造成的,就算是不斷重複啟動也不能恢復正常,因此 postfix 也會將當掉的情形紀錄在系統日誌裡,以便管理員偵錯並人工修復。

                                                                                   
fork_attempts = 5行程當掉以後,會嘗試重新啟動它 5 次!
fork_delay = 1s每次重新啟動前,先等候一秒鐘。
transport_retry_time = 60sqmgr 每隔 60 秒嘗試驅動 agent 進行分信。

 

柒、郵件地址改寫機制 vs 相關設定檔

當 cleanup 模組進行郵件過濾之前,會先依據各種設定檔呼叫 rewrite 模組,進行郵件地址改寫,這樣做的好處是可以減少標頭欄位的變化,使得過濾快取(請參考 duplicate_filter_limit 的說明)能更有效率的工作。

郵件地址改寫的順序如下:

                                                                                                                                                                                          
@hosta,@hostb:user@site 改寫成 user@sitepostfix 不支援前面那種特殊寫法
site!user 改寫成 user@site將 UUCP 格式改寫為現在使用的地址格式
user%domain 改寫成 user@domain將 % 符號去掉
user 改寫成 user@$myorigin從 local 寄出的信會缺少網域名稱,在此補上
user@host 改寫成 user@host.$mydomain將 hostname 改成 FQDN 型式
user@site. 改寫成 user@site去掉絕對網域名稱後面的小數點

根據各種設定檔改寫郵件地址:alias、canonical、virtual。

alias、canonical、virtual 等設定檔是為了達成某些特殊功能而設計的,底下說明這些設定檔的功能以及如何啟用它們:

別名對應

alias 是 sendmail 最被廣泛使用的一項功能,除了用來對應虛擬信箱外,也可以運用在郵遞清單或郵件討論群組上面,由於 postfix 在這部分完全與 sendmail 相容,因此我們就不再討論它,詳細應用方法請參考 Linux 系管師進階班講義 一文。

請在 main.cf 中加入這一行,以便啟用 alias:

alias_maps = hash:/etc/aliases

如果您的系統僅支援 dbm 格式的別名,或是透過 NIS 伺服器查詢別名,請使用底下的參數:

alias_maps = dbm:/etc/aliases, nis:mail.aliases

全名對應

這個設定檔用來建立使用者全名與帳號的關係,例如:

shane@mail.spps.tp.edu.tw    shane.lee@mail.spps.tp.edu.tw

如果網域名稱,已經設定在 $myorigin、$mydestination 或 $inet_interfaces 中就可以省略不寫,直接使用底下的語法:

shane    shane.lee

此外這個設定檔還有一個用途,就是當網域遷移時,可以將信件對應到新的網域名稱,例如:

@mail.spps.tp.edu.tw    @tp.edu.tw

當本機是 mail gateway 時,透過底下的設定可以得知哪些使用者是位於哪一台郵件主機上,分信時會分給該主機,而非分到本機的 /var/spool/mail 中:

shane    @stu.spps.tp.edu.tw(帳號相同時)
shane    s60101@stu.spps.tp.edu.tw(帳號不同時)

當設定檔輸入完成後,必須先將它雜湊成資料庫檔,以 btree 為例(與 sendmail 相容,但效能較差,建議改用 hash):

postmap btree:/etc/postfix/canonical    (檔名可隨個人喜好更改)

接著在 main.cf 中加入底下這一行:

canonical_maps = btree:/etc/postfix/canonical

如果只想對應收信人欄位則將該行,取代成:

recipient_canonical_maps = hash:/etc/postfix/recipient_canonical

如果只想對應寄信人欄位則將該行,取代成:

sender_canonical_maps = hash:/etc/postfix/sender_canonical

虛擬對應

虛擬對應僅能作用在信封裡的收信人欄位,而不會去改寫郵件標頭,與全名對應相比較,虛擬對應的功能只能算是半套。虛擬對應一般應用在兩種場合:一、將收信人欄位中的全名改成帳號名稱,二、虛擬網域對應。想啟用虛擬對應,請在 main.cf 中加入底下這一行:

virtual_maps = btree:/etc/postfix/virtual

至於虛擬對應的設定方式與全名對應相同,請自行參考前面小節的介紹。

使用者遷移

當使用者已經不再使用此信箱,而改用其它伺服器提供的信箱時,並無法通知所有的親朋好友,因此仍然會有不知情的寄信人寄信過來,這些郵件到底該如何處理呢?

首先使用者可以在自己的家目錄裡,建立 .forward 檔透過這個檔案將郵件轉寄到新的信箱,管理員也可以透過 alias 別名對應幫該名使用者轉信。雖然這樣做很人性化,但也有兩個缺點:一、轉信會增加 postfix 處理郵件的負擔,導致效能降低,二、親朋好友並不知道要把信寄去哪裡才對,所以不斷地麻煩我們!

另一種處理的方法是不要替已經搬走的使用者轉信,而直接告訴對方該寄去哪裡才對,如果管理員也不清楚新的郵件地址,直接告訴對方不要再寄信過來也可以,使用這個功能請在 main.cf 加入:

relocated_maps = hash:/etc/postfix/relocated

/etc/postfix/relocated 的設定範例如下:

shane    使用者 shane 已經不再使用此信箱了,請將信寄到 tp.edu.tw 主機,新帳號是 sean!

在提示訊息中,我們不使用 @ 符號(sean@tp.edu.tw)是為了避免被信箱收集者賣給廣告商。

郵件繞送路由

transport_maps 允許我們直接將符合條件的郵件,透過特定的方式,傳送到特定的主機,而不需要依靠 DNS MX 紀錄,譬如前面已經介紹過的延遲傳送機制外(給撥接用戶使用的),要啟用 transport 功能,請在 main.cf 加入:

transport_maps = hash:/etc/postfix/transport

底下是 transport 設定檔的應用範例,意思是要將寄給 @spps.tp.edu.tw 網域的信件,傳送到 172.16.1.6 這台主機的 8025 port:

spps.tp.edu.tw    smtp:[172.16.1.6]:8025

應用場合

優秀的管理員明白各種設定檔各有職司,就算功能可以互相取代,也不應該混合著用,例如:用全名對應機制作別名對應,用別名對應機制作虛擬對應......這樣作恐怕沒有人可以釐清其邏輯關係,將來要如何維護呢?

到底什麼情況下要用哪一種機制來實作呢?筆者給大家的建議是:

                                                                                                                                                                                                                                                           
將寄信人帳號對應成全名sender_canonical_maps = hash:/etc/postfix/sender_fullname
將收信人全名對應成帳號virtual_maps = hash:/etc/postfix/recipient_loginname
網域名稱遷移canonical_maps = hash:/etc/postfix/domain_canonical
使用者遷移relocated_maps = hash:/etc/postfix/relocated
將寄給本機帳號的信件分到其它伺服器canonical_maps = hash:/etc/postfix/individual_user
將寄給虛擬網域的郵件轉給真實存在的網域virtual_maps = hash:/etc/postfix/virtual_domain
讓使用者登入後能改用虛擬信箱寄信smtpd_sender_login_maps = hash:/etc/postfix/unaliases
將寄給虛擬信箱的郵件轉給真實存在的使用者alias_maps = hash:/etc/aliases
將郵件導向某台郵件過濾或掃毒主機transport_maps = hash:/etc/postfix/transport

 

捌、SpamAssassin

SpamAssassin 是一套用來協助過濾垃圾郵件的程式,它會針對信件中特定的比對樣式給予不同的分數,當分數超過指定的值後,該封郵件就會被當作垃圾郵件處理,處理方式依據設定的不同,會在信件標頭或郵件主旨欄位加入警告訊息。

SpamAssassin 必須結合 MTA 來使用,單獨執行並不能發揮其功效,由於該程式是使用 perl 語言開發,因此如果剛開始安裝 Linux 作業系統時沒有一併安裝,事後要補裝有一點小麻煩,安裝所需的套件如下(省略版次號碼,請自行按 TAB 補字,依順序安裝),這些 RPM 檔案可以從 RedHat 光碟取得:

perl
perl-Time-HiRes
perl-Digest-HMAC
perl-Net-DNS
spamassassin

安裝好之後,請以下列指令啟動 spamd:

service spamassassin start

並將該服務設定為開機自動執行:

chkconfig --level 3,5 spamassassin on

請用底下指令,測試程式能否成功執行:

spamc -c < /var/mail/username

假設該使用者信箱已經有至少一封郵件,這時 spamc 程式會將該郵件傳送給 spamd(127.0.0.1:783)進行評分,如果執行成功應該會看到 SpamAssassin 的評分,例如:

3.5/5.0

讓 postfix 使用 SpamAssassin 過濾郵件

確定 SpamAssassin 可以正常執行之後,接著設定 /etc/postfix/master.cf,請修改 smtp deamon 服務的設定:

smtp inet ............中間五個欄位不用修改............. smtpd -o content_filter=spamfilter:

這一行的意思是要求 smtpd 在進行完郵件過濾後,透過 spamfilter 服務進行郵件全文過濾,因此我們還得定義 spamfilter 這個服務(服務名稱可以自行修改):

spamfilter    unix    -    n    n    -    100    pipe  flags=Rq user=nobody  argv=/usr/sbin/spamc.sh -f ${sender} -- ${recipient}

這裡定義 spamfilter 服務使用 unix socket 執行,最多同時進行 100 封信的過濾(如果記憶體不足請自行修改數量),過濾方式是透過 pipe 模組以 nobody 身分啟動 /usr/sbin/spamc.sh ,並且將目前佇列中的郵件其資料結構中的 sender 和 recipient 參數讀出來,連同 -f 參數傳遞給 spamc.sh 當作參數。旗號 R 表示要把信封中的寄信人地址,以 Return-Path: 標頭插入郵件中。旗號 q 表示參數中的特殊字元要用單引號括住,以避免被當成控制字元處理,在這個例子中用來避免郵件地址中的 @ 符號被當成控制字元。

接著我們還得自己寫一支小小的 shell script,底下就是 /usr/sbin/spamc.sh 的內容(這個檔案須自己建立,之所以放在 /usr/sbin/ 是因為這個資料夾的權限比較嚴格,也比較安全):

#!/bin/sh
/usr/bin/spamc -t 30 -e /usr/sbin/sendmail -i "$@"

不要忘記將該程式的檔案權限改成 755。pipe 模組傳遞參數給上面這支程式時,會將整封郵件的內容放在鍵盤的 input 佇列中,所以我們使用 sendmail -i 這道指令將郵件從 input 佇列讀進來,"$@" 會被 spamc.sh 的參數巨集取代,也就是說 "$@" 會變成

 -f sender@sender.domain -- recipient@recipient.domain

這個字串將當成參數傳遞給 sendmail 程式,意思是要 sendmail 把參數傳遞進來的「寄信人地址 -- 收信人地址」寫在信封的寄信人欄位裡。 mail from: 與 rcpt to: 原始參數的取得,是由 smtpd 於建立 SMTP 連線時,將該字串擷取出來放在郵件佇列的資料結構中,當 master 喚醒 spamfilter 服務時,透過 pipe 當白手套,把郵件資料結構中的字串傳遞給 spamc.sh 再傳遞給 sendmail。透過這些程式的接力表演,現在終於可以把這兩個參數當作過濾的鍵值。

附帶一提:如果本機沒有安裝 SpamAssassin,想要透過別台主機安裝好的 SpamAssassin,這時候可以修改 spamc.sh:

/usr/bin/spamc -d 172.16.1.6 -p 783 -t 30 -e /usr/sbin/sendmail -i "$@"

使用這個方法前,請先確認從本機到過濾主機之間的防火牆已經放行 783 port。

刪除可疑的垃圾郵件

SapmAssassin 發現垃圾郵件的可疑對象時,會加入一個郵件標頭,至於要不要把信刪除,則不關它的事。我們可以透過 header_checks 機制(前參照第肆章 UCE 過濾的說明)把具有 SPAM 標頭的郵件刪除,然而這樣做是有風險的,萬一有些普通信件因為長得太像垃圾信而被標示為  SPAM,那就會一起被刪除!

如果你真的想刪除可疑郵件,請修改 main.cf 設置下列參數:

header_checks = pcre:/etc/postfix/header-checks

找到 /etc/postfix/header-checks 檔案,如果檔案不存在請自己建立,加入底下這一行:

/^X-Spam-Flag: Yes/    DISCARD

垃圾郵件經驗學習法

SpamAssassin 判斷一個檔案是否為垃圾郵件,是透過郵件特徵比對 hits 比率(原理有點像 proxy server),也就是說必須使用一段時間後,才能從經驗中學習到哪些郵件內容反覆不斷出現,而要學會哪些郵件是垃圾郵件,最有效的方法是透過一個垃圾信箱來學習,首先我們建立一個沒人使用的信箱,接著以此信箱為名義在 news server 上發表測試文章。

等幾天後,很快的就有一大堆垃圾信湧入該信箱,現在我們只要把信餵給 SpamAssassin 就行了,底下是透過 alias 來餵信:

fakeuser: "| /usr/bin/spamassassin -r -w fakeuser"

上面這個範例中,指令參數 -r 的意思是要 SpamAssassin 把所有郵件的寄信人信箱當成垃圾信的樣板,從此以後符合此樣板的郵件都會被認為是垃圾信。-w fakeuser 是一個非必要參數,SpamAssassin 將會以 fakeuser 信箱的名義寄警告信給對方,但是因為對方使用偽裝過的信箱,因此也沒有人會收到警告信,寄了也是白寄,建議不要使用此功能。

除了透過 alias 可以餵信給 SpamAssassin 外,我們也可以利用 .forward 來餵信,請在 fakeuser 的家目錄建立此檔案,檔案內容如下:

| /usr/bin/spamassassin -r -w fakeuser

決定 SPAM 過濾門檻

SpamAssassin 根據郵件比對的得分高低,來決定該郵件是否為垃圾信,預設值是 5 分,建議修改為 9 分。請修改 /etc/mail/spamassassin/local.cf:

required_hits 9.0

白名單與黑名單

SapmAssassin 維護一個郵件資料庫,該資料庫將透過自動學習機制來增減郵件的分數,分數高於門檻的稱之為黑名單,分數低於門檻的稱之為白名單,一旦某種特徵的郵件被評為黑名單,以後該信箱寄出的郵件都會被認為是垃圾郵件,雖然自動學習機制對於主動發現垃圾郵件很有用,但難免也有誤判的時候,這個時候我們可以透過以下命令來調整:

                                                                                                                                                                       
/usr/bin/spamassassin -W < message將該郵件加入白名單
/usr/bin/spamassassin --add-to-blacklist < message將該郵件加入黑名單
/usr/bin/spamassassin -R < message將該郵件移出白名單
/usr/bin/spamassassin --add-addr-to-whitelist=mailbox將該信箱加入白名單
/usr/bin/spamassassin --add-addr-to-blacklist=mailbox將該信箱加入黑名單
/usr/bin/spamassassin --remove-addr-from-whitelist=mailbox將該信箱移出白名單

當某個信箱被誤判為垃圾郵件,這時我們可以直接將該信箱加入白名單,例如:

/usr/bin/spamassassin --add-addr-to-whitelist=shane@mail.spps.tp.edu.tw

該信箱一旦加入白名單後,只能以手動方式移出或重新加入黑名單。如果要把具有某種特徵的郵件加入白名單(例如:校內郵件討論群組、校園電子報、網站更新通知......等,這類郵件經常被視為垃圾郵件),請先將該封郵件另存成純文字檔,接著將該信餵給 SapmAssassin 即可,請使用底下指令:

/usr/bin/spamassassin -W < myletter.eml

 

玖、amavisd-new + clamav

amavisd 用來將病毒過濾功能提供給郵件伺服器,和 SpamAssassin 一樣也是用 perl 開發的,而新版的 amavisd-new 更結合了 SpamAssassin 和許多額外設定,透過 perl NEt::Server 模組提供類似 Apache prefork 模式的效能,可以應付 ISP 龐大的郵件處理量。也就是說,使用了 amavisd-new 就不需要再去作前一章提到的 SpamAssassin 相關設定,同時也可以根據自己的需求來制定執行緒的數量。

clamav 是一套免費的病毒過濾引擎,使用者不須註冊就可以透過病毒更新程式自動更新病毒碼,而且病毒碼的維護也很迅速,每天至少會更新一次。clamav 主要用來應付硬碟檔案的掃毒工作,它可以因應硬碟 IO 動作即時監控掃毒,也可以排程進行資料夾掃描,但它卻無法與各種伺服器結合一起運作,這也就是為什麼我們需要 amavisd 的原因。更精確的說,amavisd 只是將現成的掃毒功能提供給郵件伺服器而已,它自己並不會掃毒。

設定 clamav

在這裡我們將只介紹 clamav 的安裝程序,並不打算詳細介紹 clamav 的各種功能和使用方法,有興趣的學員可以自行到 clamav 的官方網站 http://www.clamav.net/ 查看詳細的內容。首先請按這裡下載 clamav 的 RPM,使用底下指令進行安裝:

rpm -Uvh clamav-*

安裝完成後,可以使用 man clamd 來查看詳細介紹,請使用 ntsysv 或底下指令將 clamav 設定為開機時自動啟動:

chkconfig --level 3,5 clamd on

手動啟動 clamav 的方式和其它的服務一樣:

service clamd start

要更新病毒碼可以使用 freshclam 指令,如果要讓它自動更新,則可以加以下參數(意思是每天檢查更新兩次):

freshclam -d -c 2

freshclam 也是一個 deamon ,因此我們可以使用 ntsysv 或底下指令將它設定為開機時自動啟動:

chkconfig --level 3,5 freshclam on

在網路上可以找到 OpenAntiVirus 發展計畫,該計畫以 GPL 精神來整合 Linux 平台上的各種掃毒引擎,clamav 只是其中之一,其它發展中的計畫還包括:mod_vscan(在 Apache 上掃毒)、squid_vscan(在 Proxy 上掃毒)、amavisd(在 Mail 上掃毒)、pop3_vscan(在 iptables 防火牆上直接掃掉郵件病毒),有興趣的學員不妨去逛一逛。

安裝 amavisd-new

amavisd-new 的原始套件可以在 http://www.ijs.si/software/amavisd/ 取得,或按這裡下載。這個套件與 perl 模組的依存性很高,安裝異常複雜,開發者也未提供自動安裝程序,僅有一份簡要說明,使用開發者建議的方式裝,會因為 CPAN.pm 模組與特定模組有相依性的問題,導致某些特定模組安裝失敗,即使能成功安裝完成,也須自行修改 amavisd 原始程式碼,同時也無法將執行程序自動化,為了避免麻煩,請按照底下筆者的建議來安裝,安裝方式如下:

  1. 安裝 amavisd 之前,請用底下指令先安裝 CPAN:
    perl -MCPAN -e 'install CPAN';
    安裝 cpan 時,會問一大堆問題,通通按 Enter 就可以了,一直到出現底下問題:
    (1) Africa
    (2) Asia
    (3) Central America
    (4) Europe
    (5) North America
    (6) Oceania
    (7) South America
    Select your continent (or several nearby continents) [] 問所在地區,請選 2
    (1) China
    (2) Indonesia
    (3) Israel
    (4) Japan
    (5) Malaysia
    (6) Philippines
    (7) Republic of Korea
    (8) Russian Federation
    (9) Saudi Arabia
    (10) Singapore
    (11) Taiwan
    (12) Thailand
    Select your country (or several nearby countries) [] 問所在國家,請選 11
    (1) ftp://cpan.cdpa.nsysu.edu.tw/pub/CPAN
    (2) ftp://ftp.isu.edu.tw/pub/CPAN
    (3) ftp://ftp.nctu.edu.tw/UNIX/perl/CPAN
    (4) ftp://ftp.tku.edu.tw/pub/CPAN/
    (5) ftp://ftp1.sinica.edu.tw/pub1/perl/CPAN/
    Select as many URLs as you like,
    put them on one line, separated by blanks [] 問最近的映射站台,請選 5(中研院)
    剩下的其餘問題全部按 Enter 即可
  2. CPAN 裝好後,請先將剛才下載回來的 amavisd tarball 解壓縮:tar xzvf amavisd-new-<TAB補字>
  3. 切換目錄到解開的資料夾:cd amavisd-new*
  4. 測試所需套件是否已經安裝:./amavisd debug
  5. 回應訊息如下(由於每台機器已安裝的 perl 模組不一樣多,因此底下訊息僅供參考):
    ERROR: MISSING REQUIRED BASIC MODULES:
    Time::HiRes
    IO::Wrap
    IO::Stringy
    Unix::Syslog
    Mail::Field
    Mail::Address
    Mail::Header
    Mail::Internet
    MIME::Words
    MIME::Head
    MIME::Body
    MIME::Entity
    MIME::Parser
    Net::Server
    Net::Server::PreForkSimple
    MIME::Decoder::Base64
    MIME::Decoder::Binary
    MIME::Decoder::Gzip64
    MIME::Decoder::NBit
    MIME::Decoder::QuotedPrint
    MIME::Decoder::UU
    BEGIN failed--compilation aborted at ./amavisd line 123.
  6. 使用 cpan 指令安裝缺少的模組,例如:
    cpan Time::HiRes
  7. 由於某些模組可能被包在一起,安裝時會一併裝好,所以每安裝好一個就應該回頭來檢視一下,還剩哪些模組需要安裝,請再一次執行:./amavisd debug
  8. 反覆步驟 6~7 一直到出現其它錯誤訊息為止(假如很不幸剛好有的話!)例如:
    Can't locate Convert/TNEF.pm in @INC (@INC contains: /usr/lib/perl5/5.8.0/i386.........(略)
    BEGIN failed--compilation aborted at ./amavisd line 3525.
  9. 這也是相依套件沒裝好造成的(amavisd debug 模式沒發現此問題,而是由 perl 編譯器發現的),處理方式與前面相仿,只是要特別注意錯誤訊息中的 Convert/TNEF.pm 檔案,在進行安裝時要寫成:
    cpan Convert::TNEF
  10. 反覆執行 ./amavisd debug 一直到出現底下錯誤訊息為止
    find_program_path: relative paths not implemented: ./amavisd
  11. perl 模組的安裝到此已經完成,接下來就是建立服務帳號及相關目錄,這部分的工作可以透過筆者自行開發的安裝程式來作,請按這裡下載 install.sh,將該程式放在解開的 amavisd-new* 資料夾中並執行:
    chmod 755 install.sh
    ./install.sh
  12. 安裝完成後,amavisd 會自動被設定為開機啟動,你可以使用 ntsysv 或 chconfig 指令來修改啟動設定,也可以手動控制:service amavisd start

安裝外掛延伸套件

雖然在前面已經將 amavisd 裝好,也可以運作了,但考量到掃毒成效,某些延伸套件也不得不安裝,舉例來說:有人把中毒的檔案壓縮後再寄出,假如沒有安裝解壓縮引擎,那豈不是掃不到病毒。要知道掃毒是透過病毒特徵的比對,一個被壓縮過的檔案,病毒特徵都消失了,當然就比對不出來!因此要讓 amavisd 發揮最大的掃毒效益,就必須安裝各種解壓縮軟體,底下是各種 Linux 版的解壓縮程式(非 RH 9.0 的使用者請下載 Tarball 安裝),你可以連到 ftp://ftp.spps.tp.edu.tw/linux/compress/ 下載,或點選下列的超連結:

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
壓縮格式官方網站下載
filehttp://sourceforge.net/project/showfiles.php?group_id=16036RPM
compressRPM
gziphttp://www.gzip.org/RPM
bzip2http://sources.redhat.com/bzip2/RPM
nomarchhttp://rus.members.beeb.net/nomarch.htmlTarball
arcRPM
lhahttp://www2m.meshnet.or.jp/~dolphin/lha/lha-unix.htmRPM
unarjRPM
arjhttp://www.arjsoft.com/RPM
rar, unrarhttp://www.rarsoft.com/RPM, RPM
zoohttp://www.unitedlinux.com/RPM
cpiohttp://www.gnu.org/software/cpioRPM
lzophttp://www.lzop.org/RPM
freezeRPM

除了檔案壓縮部分的外掛套件外,如果希望讓 amavisd 幫我們管理 SpamAssassin,請使用 cpan 指令安裝該套件的 perl 模組,指令如下:

cpan Mail::SpamAssassin

如果想要利用 SQL 資料庫來存取中毒或垃圾郵件的黑、白名單,還必須安裝 DBD::DBI,這並不是一個模組,而是一群 perl 模組,你必須根據你使用的資料庫系統來挑選安裝,例如:mysql:

cpan DBD::mysql

如果要針對不同的使用者帳號進行不同的過濾規則設定,而使用者帳號是透過 LDAP 提供,你還必須安裝底下的模組:

cpan Net::LDAP

當然以上談到的三個外掛套件: SpamAssassin、mysql、openldap,也必須安裝才行,並不是只裝 perl 模組就可以運作,由於以上三個功能是針對 ISP 的需求而開發,校園內應該還用不上,所以不去理會也就算了!

外掛掃毒引擎

amavisd 支援 21 種掃毒軟體(包含前面介紹過的 clamav),其中大多數都是商業軟體,包括國內知名的趨勢科技和美國的賽門鐵克公司(當然得買 Linux 版,Windows 版的授權並不通用),因此在這裡我們就不介紹了!

修改 amavisd.conf

amavisd 的設定分為底下八個部分,說明如下:

                                                                                                                                                                                                                               
Essential daemon and MTA settingsamavisd deamon 的基本設定以及指定使用何種 Mail server,需要手動修改的就是這個部分。
MTA specificSMTP 通訊協定相關設定,使用預設值即可。
Logging系統日誌設定,使用預設值即可。
Notifications/DSN, BOUNCE/REJECT/DROP/PASS destiny, quarantine訂定郵件過濾政策,包括:郵件格式設定、警告訊息、中毒和垃圾郵件之處理......等等,請依需要修改,使用預設值也無妨(中毒時只警告不刪除)。
Per-recipient and per-sender handling, whitelisting, etc.訂定中毒及垃圾郵件黑、白名單管理政策,是否要透過資料庫存取、特定網域或信箱排外處理......等等,不是 ISP 應該用不到,所以我們不去理會它!
Resource limits系統資源限制,請依據自己的硬體設備等級來調整,原則上盡量調高效能才會好!(但會影響其它服務的效能)。
External programs, virus scanners, SpamAssassin外掛套件的設定,由於程式會自動偵測,所以使用預設值就可以了!
Debugging設定 debug 模式啟用時機,預設是不啟用。

在第一個部分一定得設定的有底下這些參數:

                                                                                                                                                                                                                               
$MYHOME = '/var/amavis';指定 amavis 服務帳號的家目錄,如果是使用筆者寫的 script 安裝的,這個部分不用修改。
$mydomain = 'spps.tp.edu.tw';指定郵件伺服器網域。
$deamon_user = 'vscan';指定 amavisd 服務帳號,如果是使用筆者寫的 script 安裝的,這個部分不用修改。
$deamon_group = 'sweep';指定 amavisd 服務群組,如果是使用筆者寫的 script 安裝的,這個部分不用修改。
$forward_method = 'smtp:127.0.0.1:10025';根據郵件伺服器的不同,須設定呼叫 amavisd 的方式,預設值是給 postfix 用的,如果您的郵件伺服器不是 postfix 請依文件說明修改。
$max_servers = 2;預設啟動幾個行程。
$max_requests = 10;預設每個子行程最多服務幾次要求,超過次數該子行程會重新啟動。
$child_timeout = 5*60;每次過濾郵件不可超過 5 分鐘,如果覺得病毒濾不乾淨,可以延長時間,預設是 8 分鐘。

在第四個部分底下這些參數,可依需要考量設定:

                                                                                                                                                                                                                                                                                                                                                                                                                                    
$hdr_encoding = 'iso-8859-1';指定標頭使用的字元集,使用預設值即可。因為中文字和其它雙位元字都會編成 quoted-printable code 再寄出,因此沒有相容上的問題,除非是想要啟用 utf8 才須修改。
$bdy_encoding = 'iso-8859-1';指定郵件內文使用的字元集,使用預設值即可。
$final_virus_destiny = D_BOUNCE;設定中毒郵件處理方式,預設值是發出警告信。
$final_banned_destiny = D_BOUNCE;當郵件夾帶禁止通行的檔案時(例如:exe、com、vbs、scr、pif....等等,稍後可自行修改)要如何處理,預設值是發出警告信。
$final_spam_destiny = D_REJECT;設定垃圾郵件的處理方式,預設值是拒收(郵件內容將遭到刪除)。
$final_bad_header_destiny = D_PASS;郵件標頭中含有非 ASCII 字元時,要如何處理?預設值是接受。這是垃圾信常用的招數,例如:收信人為「親愛的客戶@mail.spps.tp.edu.tw」之類的,雖然這些郵件仍然會由 postfix 再次過濾,但最好還是拒收。
當過濾政策設定為 D_PASS 時,可以利用底下參數來訂定要不要寄警告信,預設值是不要。
$warnvirussender = 1;中毒郵件要不要警告寄信者,其實這個功能還蠻實用,但是會增加伺服器負擔。
$warnspamsender = 1;垃圾郵件要不要警告寄信者,這個功能沒有用,不須設定。
$warnbannedsender = 1;郵件夾帶禁止通行的檔案時要不要通知寄信者,其實這個功能還蠻實用,但是會增加伺服器負擔。
$warnbadhsender = 1;郵件標頭含有非 ASCII 字元時要不要通知寄信者,這個功能沒有用,不須設定。
$warnvirusrecip = 1;要不要警告收信者他收到的信有毒,這個功能其實沒什麼用,因為不管有沒有收到警告信,outlook express 都會自動打開中毒郵件。
$warnbannedrecip = 1;要不要警告收信者他收到的附件檔案可能有危險,這個功能其實沒什麼用,理由同上。
$virus_admin = "virusalert\@$mydomain";請將管理員信箱改成自己常用的信箱或是透過 alias 對應到常用信箱。當管理員信箱有設定時,管理員會同步收到所有的警告信。
$banned_filename_re = new_RE(
qr'\.[a-zA-Z][a-zA-Z0-9]{0,3}\.(vbs|pif|scr|bat|com|exe|dll)$'i, # double extension
# qr'.\.(exe|vbs|pif|scr|bat|com)$'i, # banned extension - basic
# qr'.\.(ade|adp|bas|bat|chm|cmd|com|cpl|crt|exe|hlp|hta|inf|ins|isp|js|
# jse|lnk|mdb|mde|msc|msi|msp|mst|pcd|pif|reg|scr|sct|shs|shb|vb|
# vbe|vbs|wsc|wsf|wsh)$'ix, # banned extension - long
# qr'^\.(exe|zip|lha|tnef)$'i, # banned file(1) types
# qr'^application/x-msdownload$'i, # banned MIME types
# qr'^message/partial$'i, qr'^message/external-body$'i, # rfc2046
);
上面是用來設定哪些檔案要禁止通行,採用 pcre 的格式來設定,如果你對 perl 程式設計有概念,可以自行修改內容!

設定 postfix

首先在 master.cf 中先定義一個病毒過濾服務,服務名稱可以自己取:

amavis                   unix   -     -     -    -    2     smtp -o smtp_data_done_timeout=1200

這個服務將會執行 smtp client,配合稍後會作的 main.cf 的修改,該 smtp client 將會連往本機(127.0.0.1)的 10024 埠,該埠號已經 binding 給 amavisd。限制行程數為 2 個,這是為了配合 amavisd.conf 中的設定,如果覺得不夠用想修改,不要忘記一併修改 amavisd.conf。

在啟動外掛過濾程式的做法上與前面介紹過的 SpamAssassin 略有不同,後者是透過 pipe 模組呼叫一個外部 client 端程式(spamc)來啟動。而 amavisd 則由於本身並未提供 client 端程式,所以需要由 postfix 的 smtp 模組來代勞。

接著請在 master.cf 加入底下幾行設定:

127.0.0.1:10025    inet    n     -    -    -    -      smtpd
    -o content_filter=
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o smtpd_restriction_classes=
    -o smtpd_client_restrictions=
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o mynetworks=127.0.0.0/8
    -o strict_rfc821_envelopes=yes
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000

這個設定用來啟動一個 smtp deamon,以便配合 amavisd 的過濾動作,郵件從 postfix 透過 smtp client 模組傳送給 amavisd 進行病毒碼比對,比對有結果後 amavisd 會將郵件送往 10025 埠,而這個埠已經定義給 postfix smtp deamon 模組,雖然該模組會讀取 main.cf 的設定,但上面所指定的參數將會取代 main.cf 的設定,仔細看其中 content_filter= 這個參數,就會發現 postfix 將不會再啟動其它的外掛過濾機制。

細心的學員應該會想到,一旦使用了 amavisd 就不會再進行 SapmAssassin 過濾!這也就是為何 amavisd-new 必須支援 SpamAssassin 的原因,當兩個過濾引擎結合為一體時,也就不必去煩惱如何整合的問題。

配合上述的修改,請將 main.cf 中的 content_filter 參數設定為:

content_filter = amavis:[127.0.0.1]:10024

上面這一行的服務名稱須與 master.cf 中的定義匹配,如果有改過服務名稱,不要忘記一併修改。另外埠號也是可以配合 amavisd.conf 來修改,在這裡就不討論了!

還記得在前一章設定 SpamAssassin 時,曾經修改過 master.cf 中的 smtp deamon 服務嗎?這個服務是 binding 在 25 埠的主服務,不同於剛才加入的 10025 埠的 smtp deamon,當時在修改時有指定  content_filter 參數,這將會取代 main.cf 中的參數設定,導致 amavisd 過濾引擎不會被啟動,請將該參數移除:

smtp inet ............中間五個欄位不用修改............. smtpd -o content_filter=spamfilter:

改為:

smtp inet ............中間五個欄位不用修改............. smtpd

當然 spamfilter 服務也不再起作用了,可以一併刪除,不刪除也無所謂!

過濾測試

底下來測試 amavisd 的過濾功能是否有正常運作,測試時我們需要一個帶有病毒的測試檔案,這個檔案可以到 http://www.eicar.org/anti_virus_test_file.htm 取得,檔名就叫 eicar.com(這隻病毒不具有破壞能力),由於筆者的電腦有裝防毒軟體,所以無法下載這個檔案,但我們也可以直接使用病毒特徵來測試,eicar.com 的病毒特徵如下:

 X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

我們先來測試進行郵件濾後處理的 postfix smtp deamon 是否正常:

> $ telnet 127.0.0.1 10025
220 yourhost.example.com ESMTP Postfix
quit //已正常啟動並能接受指令
221 Bye
Connection closed by foreign host.

接著測試 amavisd 的過濾功能:

> $ telnet 127.0.0.1 10024
220 [127.0.0.1] ESMTP amavisd-new service ready
MAIL FROM:<test@example.com> //服務已經啟動,來寄信試試看
250 2.1.0 Sender test@example.com OK
RCPT TO:<postmaster>
250 2.1.5 Recipient postmaster OK
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: test1

test1
.

*** 250 2.6.0 Ok, id=31859-01, from MTA: 250 Ok: queued as 90B7F16F //郵件已被接受,接著寄病毒信試試看

MAIL FROM:<test@example.com>
250 2.1.0 Sender test@example.com OK
RCPT TO:<postmaster>
250 2.1.5 Recipient postmaster OK
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: test2 - virus test pattern //在標頭後面輸入病毒特徵

X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
.

*** 550 5.7.1 Message content rejected, id=16968-01 - VIRUS: EICAR-AV-Test //發現病毒,郵件已被攔截
*** 250 2.5.0 Ok, but 1 BOUNCE //發送警告信通知寄信人
*** 250 2.7.1 Ok, discarded, id=16984-01 - VIRUS: EICAR-AV-Test //中斷收信動作
*** 250 2.6.0 Ok, id=17041-01, from MTA: 250 Ok: queued as 3F1841A5F5  //警告信已經排入佇列

QUIT
221 2.0.0 [127.0.0.1] (amavisd) closing transmission channel
Connection closed by foreign host.

 

拾、寄信認證與安全連線

這裡所談的寄信認證就是指 SMTP AUTH,RedHat 所支援的 Cyrus SASL 機制可以透過三種方式進行 SMTP AUTH:

  • pwcheck:直接使用 /etc/shadow 進行帳號認證
  • pam:透過 PAM 模組可以使用 kerbros、LDAP、NIS、Samba、Radius......等認證機制
  • sasldb:使用 SASL 使用者資料庫進行認證

這三種方法中,以第一種方法最方便,因為我們不需要額外維護一個使用者設定檔(這意味著必須重設所有使用者的密碼),也不需要去設定複雜的 PAM 組態。

使用前兩種方法認證必須具備 root 身分才行,但是 postfix 預設是以 $mail_owner 來執行,所以只剩下第三種方法能利用。在這裡我們必須思考一個問題,postfix 之所以不用 root 身分執行是為了避免漏洞被駭客利用,但 postfix 本身已經提供 chroot 牢籠了,也就是說即使被駭客駭掉,也僅僅只能改變 /var/spool/postfix 內的檔案,頂多就是被利用來轉信而已,這樣還需要迴避使用 root 嗎?有關這個問題的答案,由於筆者才疏學淺,不敢給什麼建議!

先來談談第三種認證方式如何使用?

  1. 首先替所有使用者建立 SASL 密碼:saslpasswd -u realm -c user
  2. 所有帳號建好後,將 sasldb 拷貝到 chroot 牢籠中,以免 postfix 讀不到:
    cp /etc/sasldb /var/spool/postfix/etc/sasldb
  3. 接著修改該使用者資料庫的擁有人和權限:
    chgrp postfix /var/spool/postfix/etc/sasldb
    chmod g+r /var/spool/postfix/etc/sasldb

這種做法必須付出龐大的管理成本(例如:加入或移除使用者時),如果把 postfix 改成以 root 身分執行,這些問題就迎刃而解了。要讓 postfix 以 root 身分執行,請修改 master.cf:

smtp    inet    n    n    n    ...........後面欄位不用修改

接著修改 /usr/lib/sasl/smtpd.conf 的內容,將 sasldb 改成 pam,如下:

pwcheck_method: pam

有關 pam 的設定方法,在這裡不討論請自行參考系統文件,跟 SMTP AUTH 有關的設定放在 /etc/pam.d/smtp ,預設值是使用 Linux 系統認證,事實上 sendmail 就是使用這個方法。

啟用 SMTP AUTH

postfix 預設不啟用寄信認證機制,要讓 postfix 啟用 SMTP AUTH,請在 main.cf 中加入:

smtpd_sasl_auth_enable = yes

                  
注意:如果你是使用 sasldb 帳號而非 Linux 帳號,請加入底下參數,此參數用來定義帳號的領域( realm),請與你設定的 sasl 使用者匹配(saslpasswd -u realm -c user):

smtpd_sasl_local_domain = $myhostname

啟用認證功能後,加入底下的過濾規則,將使得通過認證的使用者可以隨意寄信,而不會被過濾規則阻擋,同時其它未使用認證的使用者也能夠繼續寄信(但必須通過過濾):

smtpd_sender_restrictions = permit_sasl_authenticated ......原來設定的參數加在後面......

如果只想讓通過認證的人才能寄信,未通過認證者無法寄信,請設置底下的參數:

smtpd_client_restrictions = permit_sasl_authenticated

在 postfix 中設置此選項會有一些後遺症,假設你的伺服器是對外服務的,也就是說前端並沒有一台 mail gateway 作為白手套,這樣你的郵件伺服器將無法與其他伺服器交換郵件,這是因為這些伺服器並不知道要用什麼帳號密碼來登入你的郵件主機。

如果前端有一台 mail gateway 幫我們收信,然後再轉信給我們的主機,這個時候我們的伺服器一樣會要求 mail gateway 登入,我們可以在 mail gateway 上面設置底下參數,讓它能登入轉信:

smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/saslpass
smtp_sasl_security_options = noanonymous,noplaintext

第一個參數很容易與 smtpd_sasl_auth_enable 混淆,這個參數是用來告訴 postfix 連上別人的郵件主機時,要不要進行登入。第三個參數則與 smtpd_sasl_security_options 相仿,用來定義當入時所使用的密碼機制,請詳見後文的介紹!

這三個參數設置好後,還必須在 mail gateway 上建立 /etc/postfix/saslpass 帳號密碼對照表(底下範例所用的帳號必須先在自己的郵件主機上建立好):

mail.spps.tp.edu.tw    mailhub:password

密碼機制

Cyrus SASL 可以使用多種密碼機制,從最簡單的 PLAIN(純文字密碼)、LOGIN(POP3 密碼,編成 base64)...... 到安全的 DIGEST-MD5、CRAM-MD5,後兩者必須結合 SSL/TLS 安全連線才能使用。postfix 使用何種密碼認證是由 smtpd_sasl_security_options 參數來決定:

                                                                                                                                           
noplaintext關閉純文字密碼認證功能(包含:PLAIN 和 LOGIN)
noactive防止以暴力法破解密碼
nodictionary防止以字典法破解密碼
noanonymous禁止匿名登入
mutual_auth只允許使用 SASL 2.0 認證方式

postfix 預設禁止匿名登入,但是允許使用純文字密碼,當然我們知道使用 PLAIN 和 LOGIN 一樣都不安全,因為密碼很容易被監聽封包的程式盜取。因此我們建議使用 SSL/TLS 安全連線來進行登入,底下參數將同時允許安全連線及一般連線:

smtp_sasl_security_options = noanonymous
smtpd_use_tls = yes

如果想禁止使用純文字方式登入,請將上面的參數改成像這樣,如果 openSSL 還沒安裝設定好,請不要啟用這個功能:

smtpd_tls_auth_only = yes

啟用安全連線

在 postfix 中啟用安全連線機制,你必須先安裝好 openSSL 套件,postfix 的 smtpd 模組在進行安全連線時會呼叫 Postfix/TLS 這個模組來管理安全通道,這就相當於 sendmail 中的 MSA。要啟用 MSA,請修改 master.cf:

smtps            inet    n       -       y       -       -       smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
submission    inet    n       -       y       -       -       smtpd -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes

另外在 MSA 進行連線時,需要使用亂數產生一次性密碼,該亂數可藉由系統亂數裝置 /dev/urandom 產生,如果你的系統找不到此裝置,請設定底下的模組程式來代替:

tlsmgr    fifo    -       -       y       300     1       tlsmgr

安裝憑證

postfix 安全連線必須要有金鑰才能運作,因此利用 openSSL 產生認證所需的金鑰和憑證(放在同一個檔案裡):

cd /usr/share/ssl/certs
make /etc/postfix/server.pem

現在必備的憑證檔案都有了,我們可以設定 mian.cf 讓 postfix 讀取憑證:

smtpd_tls_cert_file = /etc/postfix/server.pem
smtpd_tls_key_file = $smtpd_tls_cert_file

連線測試

我們設定好相關參數後,可以將 postfix 重新啟動並使用 telnet 進行底下連線測試:

[root@linux postfix]# telnet 172.16.11.1 25
Trying 172.16.11.1...
Connected to 172.16.11.1.
Escape character is '^]'.
220 linux.spps.tp.edu.tw ESMTP Postfix
ehlo test.com //由於是從主控台連線,並不會過濾 HELO 命令字串
250-linux.spps.tp.edu.tw
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS //系統支援安全連線
250-AUTH PLAIN LOGIN //系統支援寄信認證功能
250-XVERP
250 8BITMIME

當 main.cf 啟用 smtpd_tls_auth_only = yes 參數時,進行底下測試:

auth plain //測試能否以純文字方式登入
538 Encryption required for requested authentication mechanism
starttls //測試能否開啟 SSL/TLS 連線
220 Ready to start TLS
quit

標籤: Linux

SAMBA ACL

1.Samba 要做Acl 不一定要有LDAP
2.File system ACL功能一定要支援
3.Samba ACL 功能要開
4.可在Samba中作多重User的權限控制,但沒法作"讓某一位User新增檔案後
,就不能刪檔案"的功能
5.但可做到可變更自己新建的檔案或目錄,但不能刪除他人的,就算完全控制也
沒用,在目錄中加上 Sticky bit。當然也不用ACL來控制也可
這是我的範例 :User sky 在/test 可新增但不能刪其他目錄、User kevin
可在/test完全 控制包含sky建立的檔案目錄
#chmod -R 1777 /test
[test]
path = /test
browseable = yes
public = yes
writable = yes
valid users = sky,kevin
write list = sky,kevin
admin users = kevin
force create mode = 1777
force directory mode = 1777
如此kevin 都可完全控制/test中的權限(因為它是主管)
sky 卻不能刪kevin建立的檔案
標籤: Linux

Embedded Linux資源好站

介紹一些Embedded Linux資源好站連結網址 :

http://people.debian.org.tw/~moto/embedded/Embedded_Linux_GUI/Embedded_Linux_GUI.html



Embedded Linux 底下幾種 GUI 系統架構

http://people.debian.org.tw/~moto/embedded/Embedded_Linux_GUI/Embedded_Linux_GUI-2.html



嵌入式作業系統& MiniGUI 論壇

http://www.minigui.org/cgi-bin/lb5000/leoboard.cgi



嵌入式研究網:: 瀏覽論壇- Embedded linux

http://www.cnemb.com/index.php?name=PNphpBB2&file=viewforum&f=10



嵌入式系統學習工具 Minidoochun 工作坊嵌入式系統學習工具 Minidoochun 工作坊

http://www.openfoundry.org/article.pl?sid=05/03/09/1626243


Embedded Linux Consortium(ELC)

ELC是一個業界非牟利組織,專門推動Linux在內嵌裝置的發展及應用,成員來自不同的內嵌Linux商業機構,達致群策群力的效果.


http://www.embedded-linux.org



直擊嵌入式Linux開發資源

http://www.eedesign.com.tw/article/Spotlight/0503_1_linux/0503_linux.htm



VOCAL  以Open Source VOCAL進行開發實作

http://www.vovida.org/applications/downloads/vocal



Mini Linux

http://igloo.its.unimelb.edu.au/linux-online/minilinux.html#Appendix_B



『微碼科技』嵌入式系統、嵌入式軟體

http://embyte.com/down_view.asp?id=450

標籤: Linux

ProFTP 教學

                                                                           
ProFTPD server架設

這一章我們介紹如何架設自己的ftp伺服器.
在Mandrake 中 ,長期以來都是以proftpd為主要的ftp伺服器
所以首先也是相同 的我們簡單介紹一下如何架設自己的ftp伺服器.

首先 我們必須要把我們所需的元件安裝上!
一樣的使用urpmi來進行安裝:

                  


#urpmi proftpd


ProFtpd本身和 apache有很多的相似點.
在設定及一些特色上都非常的相近,也就是說,可以學一多用
這個我們以後再來談!

如果您有使用X的話請使用 drakxservices
或ntsysv來設定讓他在開機 時啟動

我們直接對他進行驅動先
                  


#service proftpd restart
Shutting down proftpd: [ OK ]
Starting proftpd: [ OK ]



這樣您的ftp就裝好了也可以使用了.很神奇吧.
您可以直接用您的ftp程式連結您的ftpserver
密碼為您系統使用者 的密碼!

接下來我們針對ProFtpd的設定來進行一些簡單的說明.
讓使用者只可以在自己的家目錄中進行上傳及下載
為了安全上的考量,不希望使用者讀取自己家目錄之外的檔案.
我們必須要限制使用者的活動範圍:
首先我們開啟 /etc/proftpd.conf
找到這一行
                  


# DefaultRoot /home/foo foo


他的意思為"預設的根目錄為何"
如果您要指定一個使用者的根目錄
設定說明:
DefaultRoot [預設根目錄路徑] 使用者帳號

例:
                  


DefaultRoot /home/jacch jacch


這樣設定就是讓jacch這一個使用者只可以在 /home/jacch這一個目錄中運作
當然如果要一個一個的設定真的太累了.
所以我們用簡單的方式:
                  


DefaultRoot ~


這個毛毛蟲是指自己的家目錄.
註:
在unix系統中 "~" 是指家目錄,
相當於$HOME
例如: 回到家目錄我們可以這樣執行
#cd ~
或者
#cd $HOME

這樣想就會比較簡單一些了.

架設公開型的匿名ftp伺服器
我們在 /etc/proftpd.conf中 加入這一些
                  


<Anonymous ~ftp>
User ftp
Group ftp
# 設定匿名者的權限
UserAlias anonymous ftp

#限制連線人數50人
MaxClients 50
#不需shell
RequireValidShell off
#不需密碼
AnonRequirePassword off

#歡迎訊息檔
DisplayLogin welcome.msg
#目錄說明檔
DisplayFirstChdir .message

#限制匿名者無法寫入
<Limit WRITE>
DenyAll
</Limit>

</Anonymous>


再重起您的ftp伺服器就可以允許匿名者進入了!
就像很多的大學檔案系下載系統一樣!


apache和proftpd都可以交由 xinetd來管理.
不過在運行上您必須做一定的考量.
如果您 的站台會經常有人在使用這樣的功能 的話.
建議您可以讓他獨立運行,如果您只是單純的要讓自己或少數家人或朋友使用的話,
建議您可以使用xinetd,因為他會比較節約系統資源.
改天再來討論一下二者 的不同!^ ^


 
proftpd.conf 簡易設定

相關連結 範例或相關連結 || 作者: || 時間:2003-07-17 21:06 || 最後更新:2003-07-17 21:06
# This is a basic ProFTPD configuration file (rename it to
# 'proftpd.conf' for actual use. It establishes a single server

# and a single anonymous login. It assumes that you have a user/group

# "nobody" and "ftp" for normal operation and anon.

ServerName "---SEXJACK'S FTP SERVER---" #伺服器在登入時所顯示的伺服器名稱


ServerType standalone #設定伺服器是否常駐於記憶体內;standalone為是;inetd為FTP不常駐於記憶內


DefaultServer on #這部分,若是為單單只架FTP server的話,沒有這一行的。因為,一個IP同時架了多個的伺服器,而這行在為架設一個標準隨虛擬FTP伺服器

ServerIdent off #於登入時,是否顯示所使用的伺服器是何種軟体架設的,off的話是不顯示,反過來當然是on


# Allow FTP resuming.


# Remember to set to off if you have an incoming ftp for upload.

AllowStoreRestart on #這部份為設定是否可關閉重新啟動

#ServerAdmin sexjack@yahoo.com.tw #此行為設定伺服器管理者的E-mail,若sever有問題,則會寄信給管理者


#DefaultRoot ~ #此行為設定FTP的使用者只能在自已的家裡活動


# Port 21 is the standard FTP port.

Port 21 #設定於登入時,主機是Listening那一個port,若為inetd,則自行設定會無效


# Umask 022 is a good standard umask to prevent new dirs and files

# from being group and world writable.

Umask 022 #設定檔案權限遮罩,022則為755,不用我解釋了吧??



# To prevent DoS attacks, set the maximum number of child processes

# to 30. If you need to allow more than 30 concurrent connections

# at once, simply increase this value. Note that this ONLY works

# in standalone mode, in inetd mode you should use an inetd server

# that allows you to limit maximum number of processes per service

# (such as xinetd)

MaxInstances 30 #設定伺服器於同一時間內可以處理的程序有幾筆,若severtyep設為standalone的話,可設低一點,以避免駭客的DoS攻擊



# Set the user and group that the server normally runs at.

#這空行為在設定可存取此伺服器的隨使用者和群組

# Normally, we want files to be overwriteable.


<Directory /var/ftp> #為登入時想進入的目錄位置

AllowOverwrite on
#是否刪除錯誤的存檔

DeleteAbortedStores off
</Directory>



# Needed for NIS.


PersistentPasswd on #是否需要密碼驗証?若為非開放的FTP,最好是為on



# Default root can be used to put users in a chroot environment.

# As an example if you have a user foo and you want to put foo in /home/foo

# chroot environment you would do this:
# DefaultRoot /home/foo foo




<Global> #標隼的FTP SERVER的設定值

DefaultRoot /var/www/html root #這裡我因為我WBB SERVER在編製,因此特將root指定至/var/www/html的目錄下

DefaultRoot /var/ftp users #這裡設定為user群組所登入的FTP目錄位置

AllowStoreRestart on #這部份為設定是否可關閉重新啟動
MaxClients 4 "IT IS MAX" #此為設定取多可同時在FTP上的人數;後面的那句"IT IS MAX"為後面第五人無法登入時所看到的訊息

RootLogin on #設定權限管理者是否能以root帳號登入,平常不建議開啟

MaxClientsPerHost 4 #....不會翻了....也不大了解

</Global>


UseReverseDNS on #是否開啟DNS


TimeoutNoTransfer 600 #多久的時間沒反應就停止連線,以秒為計算單位

#允許root可登入
RootLogin on

#允許上傳續傳
AllowStoreRestart on

#同個 IP 最多能登入幾個 Session 同一個 IP 只能登入一次
MaxClientsPerHost 1

#下面兩種選一種設定
#設定 FTP 預設路徑在/home/ftp下;所有的帳號進入時都會到這個目錄下
DefaultRoot /home/ftp !david =>除了david之外

#根目錄是自己的home目錄 =>所有的帳號都會到家目錄
DefaultRoot ~ !david =>除了david之外

#流量控管 (25KB/Sec)
RateReadBPS 25600
RateReadFreeBytes 5120
RateReadHardBPS on

#只允許192.168.1的網段連上ftp
<Limit LOGIN /*>
Order allow,deny
Allow from 192.168.1.
Deny from all
</Limit>

#限制一個目錄下的權限
<Directory /home/ftp/upload/*>

<Limit READ> #可讀取
AllowAll
</Limit>

<Limit WRITE> #可寫入
AllowAll
</Limit>

<Limit DELE> #不可刪除
DenyAll
</Limit>

<Limit RNFR> #不可更名
DenyAll
</Limit>

<Limit MKD> #不可創造資料夾
DenyAll
</Limit>

<Directory>
標籤: Linux

DOM 的製作 FOR LINUX

作為嵌入式系統,使用環境通常都比較惡劣,而應用又比較簡單。為系統的穩定通常都需要使用DOM、CF卡一類的存儲設備來代替硬碟。因此需要製作一個小於32M的linux運行系統。
使用到的軟體包括:syslinux, busybox, linux kernel 2.4.18, redhat 9
 作為嵌入式系統,使用環境通常都比較惡劣,而應用又比較簡單。為系統的穩定通常都需要使用DOM、CF卡一類的存儲設備來代替硬碟。因此需要製作一個小於32M的linux運行系統。
一、準備軟體環境
1.一套linux的運行環境,選用redhat 9的基本安裝,需要能夠編譯內核方便以後重新編譯內核;
2.bootloader軟體,選用syslinux中的extlinux;
http://syslinux.zytor.com
3.主要系統應用程式,選用busybox;
busybox能夠以一個小型的應用程式提供整個命令集的功能。
http://www.busybox.net


二、製作可以啟動的盤

fdisk /dev/hdc1
本實驗使用cf盤 cf to ide轉換卡,用fdisk對盤進行分區,但這一步驟需要確認哪一個設備是cf卡。這個可以同dmesg來看。

mke2fs /dev/hdc1
格式化cf盤為ext2格式

mkdir /mnt/cf
mount /dev/hdc1 /mnt/cf
extlinux /mnt/cf
安裝bootloader到cf卡上。

完成以後cf卡基本可以引導,現在進行一次重啟動測試一下。
實驗結果,只需要看到Extlinux 的資訊即說明安裝成功。

三、安裝內核和配置引導
由於目前只是實驗先不進行內核裁減,直接使用redhat 9的內核檔。
mount /dev/hdc1 /mnt/cf
cp /boot/vmlinuz-version /mnt/cf/
cp /boot/initrd-version.img /mnt/cf/

vi /mnt/cf/extlinux.conf
寫入一下內容:
default emblinux
display logo.txt
label emblinux
kernel vmlinuz
append root=/dev/hdc1 initrd=initrd.img splash=silent ide=nodma

首先要注意的檔案名為extlinux.conf,因為在syslinux和isolinux中都是使用.cfg的尾碼,這樣可能會給人一個錯覺認為也是用.cfg。結果,我在這個地方花了不少的時間,終於找到一個帖子提到使用extlinux.conf。
另外增加ide=nodma只適用在使用cf卡的情況,這個可以避免啟動時因為讀盤超時而無法繼續的錯誤(0x58)。

完成這些步驟,內核就能引導。
這一步完成,重啟能看到內核引導資訊即為成功。
四、安裝主要應用程式和運行環境
mount /dev/hdc1 /mnt/cf

創建需要的目錄
cd /mnt/cf
mkdir etc bin sbin var usr lib tmp proc initrd dev

根據busybox的說明編譯,然後安裝。
make PREFIX=/mnt/cf install

複製基本的dev文件
cp -arf /dev/* /mnt/cf/dev/
需要進行一些裁減,否則會超過限制大小。

複製busybox下的examples/bootfloppy/etc目錄下檔
cp -arf examples/bootfloopy/etc/* /mnt/cf/etc

編輯init.d/rcS文件
vi /mnt/cf/etc/init.d/rcS
增加
/bin/sh

複製lib
先用ldd busybox看需要哪些so
把相應的so複製到lib目錄下,這一步比較關鍵。
複製/lib/modules和/lib/security目錄到/mnt/cf/lib目錄下,並進行一些裁減。
完成這最後一步,整個啟動盤已經可以正常啟動,並進入shell下。
 from http://www.linuxjiaocheng.com/




******************************************************************************************************


DOM製作流程
專案基本結束,這個是其中系統裁減的一個總結文檔,不知道有沒有人感興趣:)

=============================================

前言:
為了完成用戶的需求,需製作一個完整的環境供AP運行,且存在一些約束條件。

關鍵字:
DOM Kernel Busybox X-Window Window-Manager Interbase nvidia cutdown

目標說明:
在一個64M的DOM(Disk on module)上建立可以運行完整的AP的環境

約束條件:
1、可利用的總空間為64M,由DOM提供,但實際可用空間只有53-59M,原因可能與設備檔和DOM本身有關,未確定
2、顯卡為nvidia系列
3、kernel選用2.4.20,沒有使用redhat自帶的版本。採集卡的Driver目前還只能在2.4.20的kernel下編譯,由於其移植性較差,已經開始考慮重新整理成可適合kernelversion大於2.4.25的所有kernel,參考bttv的最新實現
4、資料庫選用interbase系列,目前使用的為firebird-1.5(firebird為interbase的開源實現,介面和interbase基本相同)。
5、其他附屬的功能要求,在後面的文檔中會有說明

製作流程:
某些部分的原理和實現沒有辦法寫的很全面,但基本上會提供一些url的連接,供相關人員參考。基本上按照製作流程來寫,前後相互牽連的部分不做特別說明。

一、Kernel的選擇和編譯:
由於driver的緣故,只能使用2.4.20的kernel。2.4.20和2.4.25都有對Driver做過嘗試,其他版本的kernel沒有試過,應該是可以的,尚未確認。在2.6的kernel上無法編譯,目前確定的原因是makefile有問題,估計做一些相應的修改還是可以的,可參考bttv的makefile(http://linux.bytesex.org/v4l2/bttv.html)。
回到kernel上來,基本上的編譯原則是儘量減去不需要的部分,以及除了一些需要臨時載入的Driver儘量不要出現module。由於上面所說的理由,DOM中使用的kernel為原始的2.4.20,可以從http://www.kernel.org下載,本文檔的附加檔裏也可以找到。
另外,由於需求的定義,系統啟動時需要顯示splash畫面,所以kernel還需要加入bootsplash功能,這個功能是第三方提供的,作為補丁加入kernel。作法如下:

1、打內核補丁並編譯內核
假設內核原始檔案安裝在/usr/src/linux/。下載bootsplash 3.07(地址:ftp://ftp.suse.com),然後:

yourbox:~ # cd /usr/src/linux
yourbox:/usr/src/linux # patch -p1 < /path/to/bootsplash-3.0.7-2.4.20-vanilla.diff
yourbox:/usr/src/linux #

配置內核,如make menuconfig或make xconfig,在”Console drivers” -> “Frame-Buffer support” 選擇 “VESA VGA graphics console” 或其他與你的顯卡相應的驅動。打開 “Use splash screen instead of boot logo”. 在 “Block Devices”中打開”Initial Ramdisk support”,保存配置並編譯內核,將生成的內核拷到/boot 下,並修改lilo或grub的配置檔以使用新的內核來啟動。

2、加入圖片
下載並安裝splash工具:ftp://ftp.suse.com/pub/people/

# cd ~/splash
# tar xvjf splashutils.tar.bz2
splashutils/
splashutils/Makefile
splashutils/splash.c
[..]
splashutils/ChangeLog
splashutils/COPYING
# cd splashutils
# make splash
gcc -Os -Wall -c -o splash.o splash.c gcc -Os -Wall -o splash splash.o
strip splash
# cp splash /sbin/
# cd ..

將圖片及相關的資訊加入到initrd中去:
/sbin/splash -s -f /etc/bootsplash/themes/yourtheme/config/bootsplash-1024x768.cfg >> /boot/initrd.splash

圖片在附件檔中

3、運行lilo更新配置檔(grub就不用更新了),重新啟動,如果一切正常,就可以看到啟動畫面了。同時會有這樣一些資訊:

vesafb: framebuffer at 0xf0000000, mapped to 0xdc816000, size 65472k vesafb: mode is 1024x768x16, linelength=2048, pages=41 vesafb: protected mode interface info at c000:5137 vesafb: scrolling: redraw
vesafb: directcolor: size=0:5:6:5, shift=0:11:5:0 Looking for splash picture.... silenjpeg size 11165 bytes, found (1024x768, 4912 bytes, v3) Got silent jpeg.

kernel的config檔比較大,在附件中有,這裏就不列舉了。

編譯過程:
1、獲取2.4.20的原始kernel壓縮包(linux-2.4.20.tar.bz2)
2、tar xvjpf linux-2.4.20.tar.bz2
3、cp config-2.4.20 (kernelsource)/.config #拷貝config-2.4.20到kernel source所在目錄中並以.config為新的檔案名
4、cd (kernelsource)
5、make menuconfig #不需要做任何改動,直接退出
6、make dep && make bzImage && make modules && make modules_install && make install
7、如果沒有問題,繼續下一步,如果有問題,請檢查編譯環境是否正確,並重複step 6
8、此時kernel已經編譯完畢,需要做兩件事情,一是保存將來放入DOM的文件,二是將當前的發行版的kernel換成2.4.20,以便後面的nvidia顯卡dirver的正確編譯。
9、創建一個保存目錄,比如~/kernelbackup
10、cp (kernelsource)/arch/i386/boot/bzImage ~/kernelbackup # 保存kernel
11、cp /lib/modules/2.4.20 ~/kernelbackup/ -arf # 保存編譯出的所有modules
12、如果當前的發行版使用的是grub,則修改/boot/grub/grub.conf(如果沒有這個檔可以修改/boot/grub/menu.lst,都是一樣的),如果是lilo,修改/etc/lilo.conf。下面是grub的修改說明,lilo的修改辦法可以參考相關文檔:

# add below to your grub.conf
title new kernel(2.4.20) # title just, u can modify it anywhere
root (hd0,0) # root setup
kernel (hd0,0)/boot/bzImage-2.4.20 ro root=/dev/hda1 vga=791 splash=silent # just.....
initrd (hd0,0)/boot/initrd.splash # splash that show when booting of OS

13、reboot
14、選擇新的啟動選項,檢查是否正確

二、Shell的選擇和編譯:
到目前為止,kernel的裁減基本上結束,下面是shell的選擇和編譯。 對於linux而言,kernel只是提供系統調用介面,本身無法直接使用,需要外部shell的支援。一般shell有幾種選擇,如bash、ash、busybox等,由於busybox相對尺寸最小,而且提供了基本完整的功能,所以選擇busybox做為系統的shell。詳細資訊參閱www.busybox.net,附件中有目前使用的busybox版本。busybox的流程主要是編譯和安裝,從而聯合kernel組成一個基本系統。 busybox的配置檔在附件中有,這裏就不列舉了。

編譯過程:
和kernel基本相似
1、解壓busybox
2、複製config到busybox源碼目錄下
3、make menuconfig #不做改動即可退出
4、make dep && make

三、基本系統的安裝:
到此時,busybox和kernel都已經準備完畢,接下來需要一個分區來安裝他們。 不管是使用一個單獨的分區還是完整的DOM都可以,但總歸需要一個完整的目標分區供使用。假設目標分區為/dev/hdc1,下面的說明會以此為基準。 需要說明的一點是,一開始儘量不要用DOM直接調試,因為其速度和容量都十分的不好,會造成調試的困難,直到調試後期再使用是個比較不錯的主意。

現在進入基本系統的組裝:
# fdisk /dev/hdc1 and format it with ext2 or ext3. My suggest is ext3.
Mount /dev/hdc1 /mnt/dom # mount目標分區
mkdir /mnt/dom/boot
mkdir /mnt/dom/boot/grub
cp (kernelbackup)/bzImage /mnt/dom/boot # copy kernel to dom
cp (kernelbackup)/initrd.splash /mnt/dom/boot # copy initrd splash to dom
mkdir /mnt/dom/lib
mkdir /mnt/dom/lib/modules
cp (kernelbackup)/2.4.20 /mnt/dom/lib/modules -arf # copy all modules to dom cd (busyboxpath)
make PREFIX=/mnt/dom install # install busybox to dom
現在,一個基本系統基本安裝完畢,接下來是配置問題:
mkdir /mnt/dom/etc # all config here
mkdir /mnt/dom/dev # device file
mkdir /mnt/dom/mnt
mkdir /mnt/dom/proc
mkdir /mnt/dom/tmp
mkdir /mnt/dom/var
mkdir /mnt/dom/lib
mkdir /mnt/dom/root # home of root
mkdir /mnt/dom/usr # X window-manager lib, etc
cp (busyboxpath)/examples/bootfloppy/etc/* /mnt/dom/etc -arf # base config
cp /dev/* /mnt/dom/dev -arf # device file. Will cutdown part of all

下面是加入必需的連接庫:
1、ldd busybox
2、查看busybox使用了哪些連接庫,拷貝至目標分區中同樣的路徑下,一般為/lib
3、再用ldd查看連接庫是否還有需要的庫檔,如果有同樣拷貝到目標分區中
4、重複第三步
5、cp /dev/* /mnt/dom/dev/ -arf # 後期還會做一些裁減
Grub配置:
# add below to your grub.conf
title new kernel(2.4.20) # title just, u can modify it anywhere
root (hd0,0) # root setup
kernel (hd0,0)/boot/bzImage-2.4.20 ro root=/dev/hda1 vga=791 splash=silent # just.....
initrd (hd0,0)/boot/initrd.splash # splash that show when booting of OS

現在可以做一些測試,看看基本系統是否工作正常。執行下麵的命令
cd /mnt
mkdir dom
mount /dev/hdc1 dom # mount it
chroot /mnt/dom /bin/sh
如果你看到登陸成功的資訊就表示基本系統沒有什麼問題了。

重新啟動機器,並選擇新的啟動選項,看看基本系統是否正常,如果有問題,重新檢查前面的步驟是否做的有問題。如果啟動正常,那麼,基本系統就基本完備,可以繼續後面的步驟了。

四、Xfree86的裁減和安裝:
基本系統已經正常工作,接下來就是xfree86的裁減和安裝,首先切換到目標分區並確定系統處於正常工作狀態。
在這裏需要說明一下Linux的目錄分佈和作用情況。首先通過“ls /”列舉一下根分區,大致會有以下目錄:
bin boot dev etc home lib mnt opt proc root sbin tmp usr var
下面逐一說明:
bin: shell的工作目錄,比如sh、bash、mount等命令
boot: kernel、ramdisk檔以及grub(lilo)的存放目錄,有的發行版會為此目錄單獨創建一個分區,以防止系統崩潰的影響。在DOM中是不考慮的。
dev: 所有的設備檔都存放在這裏,比如/dev/video0、/dev/hda等。全部設備檔大概要佔用400K左右的空間,但似乎全部拷貝過來的話,DOM總是會報空間不足,但實際還是有空間的,原因不明。目前的做法是對設備檔做了一些調整,去除了不需要的部分,參考後面的檔列表。
etc: Ap配置以及系統配置存放目錄
home:普通用戶的工作目錄根
lib:基本庫存放目錄
mnt:mount
opt:看情形,目前是用做存放firebird
proc:系統工作所需的目錄
root:一般為root的工作目錄,可以調換
sbin:常規命令存放目錄
tmp:一般為臨時目錄
usr:所有擴展命令和xfree86,以及window-manager所在目錄,是系統最大的一個目錄,包含內容最多。對於DOM來說,主要是存放連接庫、xfree86、字體、window-manager等。
Var:臨時目錄,一般在發行版中為存放website檔、安裝檔以及一些log資訊等,在DOM中只作為臨時目錄使用

大致的分佈情況說明完畢,接下來就是具體的裁減工作了。 實際上,xfree86有一些替代實現,比如freedesktop、fb等,甚至framebuffer也是一個可以考慮的方向,但是由於AP使用了nvidia顯卡提供的opengl 1.3介面,導致目前的唯一選擇就是xfree86。也許有其他更小的實現,希望能在以後改進。 進入正題,xfree86的主程序實際上就是一個XFree86,位於/usr/X11R6/bin,有的發行版下X是一個指向XFree86的連接,有的卻是一個完整的程式,但不管怎麼樣,Xfree86就是最主要的程式。現在,在目標分區上mount發行版,以便可以拷貝我們所需要的:
cd /mnt
mkdir dist # create mount path of distribute
mount /dev/hda1 dist # /dev/hda1 is root partition of your distribute. Check it.
現在/mnt/dist就是發行版所在的位置。

mkdir /usr/X11R6
mkdir /usr/X11R6/bin
mkdir /usr/lib
mkdir /usr/X11R6/lib
創建一些需要的目錄。

cp /mnt/dist/usr/X11R6/bin/XFree86 /usr/X11R6/bin -arf 拷貝xfree86的主程序。
cp /mnt/dist/usr/bin/ldd /sbin # copy ldd that is used to cutdown
ldd是用來在DOM的環境中做裁減工作的,直接輸入ldd看看是否可以運行,如果執行有問題,一般是相關的連接庫不全,按照之前的方法複製過來就可以了。

現在,要查看XFree86需要哪些連接庫和配置檔,以保證其可以運行起來。
cd /usr/X11R6/bin
ldd Xfree86
此時會看到很多的連接庫,那麼就需要把這些庫全部從發行版上複製過來,可以直接複製到相對應的目錄下,比如/usr/lib/或者/usr/X11R6/lib/下,需要注意的一點是,有些庫本身還會需要其他的庫,可以一層層的ldd出來,網路中有人做過自動工作的工具,但還是手動裁減比較可靠。全部的庫導入完畢後,嘗試運行/usr/X11R6/bin/XFree86,會看到一些出錯資訊,提示/etc/X11/XF86Config不存在,那麼就將發行版中的/etc/X11目錄全部複製到目標分區中:
cp /mnt/dist/etc/X11 /etc -arf
實際上這個目錄中不是全部都需要的,某些部分是可以刪除的,但我沒有具體實驗,而且尺寸並不是很大,就全部使用了。
現在再執行/usr/X11R6/bin/XFree86,會提示一些庫沒有找到,但實際上之前已經全部複製過來了,原因是從shell執行一條命令的時候,命令所需要的庫是從以下的途徑得到的:
1、搜索/lib
2、搜索/etc/ld.so.cache
之前所複製的庫檔大半是放在/usr/lib和/usr/X11R6/lib下的,而且現在的/etc下還沒有ld.so.cache檔,要生成這個檔就需要ldconfig這個命令:
cp /mnt/dist/sbin/ldconfig /sbin -arf
現在ldconfig是有了,但還需要與之有關的配置檔/etc/ld.so.conf,所以:
vi /etc/ld.so.conf
/usr/lib
/usr/X11R6/lib
現在執行ldconfig,就會在/etc/下出現一個ld.so.cache。以後如果有新加入的庫檔,而且不是存放在/lib/下的,都按照這個步驟來導入。現在,執行/usr/X11R6/bin/XFree86,出現的錯誤提示為無法打開/var/kdb和/var/log。
這裏需要說明配置上的一個修改,cat /etc/fstab,會看到現在的fstab只有一句話:
none /proc proc defaults 0 0
現在要加入一些新的配置,新的fstab如下:
proc /proc proc defaults 0 0
none /var tmpfs defaults 0 0
none /tmp tmpfs defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0
none /data tmpfs defaults 0 0
現在/var、/tmp和/data都是在記憶體中了,其中/data是將來mount磁片的地方,需要手動mkdir出來:
mkdir /data
現在修改/etc/init.d/rcS:
#! /bin/sh

/bin/mount -a

mkdir /var/log
mkdir /var/lib
mkdir /var/lib/xkb

重啟DOM,現在應該存在/var/log、/var/lib、/var/xkb目錄了,當然這些目錄只是存放在記憶體中,所以需要每次啟動時臨時創建。
再運行XFree86,應該會看到一個錯誤的提示,說明還需要opengl的一些連接庫,從發行版中複製出來就可以了。
嘗試在目標分區中執行/usr/X11R6/bin/XFree86,如果沒有進入X介面,需要檢查之前的步驟是否有沒有做對的地方。

五、Window-Manager的選擇安裝:
到目前為止,X已經完全移植到DOM中了,但一個包含基本系統和X的系統還不能滿足AP的要求,接下來是Window-manager的選擇和安裝。
kde和gnome是無法安裝到DOM中的,尺寸太大,可能的選擇包括twm、fluxbox、windowmaker、icewm等,但需要滿足以下幾個條件:
1、有caption,而且Modal dialog不能被切到後臺,以符合用戶的操作習慣
2、X上不能有任何多餘的部分,即除了AP,不存在任何UI,如taskbar之類
3、尺寸要小
4、最好不要有system menu和system buttons

經過挑選,最終選擇了fluxbox作為DOM的window-manager,尺寸相對其他window manager要大一些(10M),但是較好的滿足了以上條件。

安裝過程:
1、下載fluxbox
2、./configure
3、make
4、make install
5、複製相關檔到DOM的相同目錄中
6、測試,如果有問題,重複第一步
等window manager安裝完畢後,一個包含基本系統和window的環境就創建成功了。接下來就是一些附屬部件的裁減和安裝了。

六、其他部件的裁減和安裝:
先切換到發行版。最後定義的資料庫引擎為Firebird 1.5,所以先下載firebird 1.5(http://prdownloads.sourceforge.net/...0-0.i686.tar.gz),然後在發行版上先安裝。firebird會安裝在/opt目錄下,將/opt/firebird複製到目標分區中:
cp /opt/firebird /mnt/dom/opt -arf

然後修改配置檔:
vi /mnt/dom/etc/init.d/rcS
#! /bin/sh

/bin/mount -a

mkdir /var/log
mkdir /var/lib
mkdir /var/lib/xkb

/opt/firebird/bin/fb_lock_mgr &
/opt/firebird/bin/fb_inet_server &

現在切換到目標分區中,會看到進程列表中有一個fb_lock_mgr,這說明firebird已經安裝成功。

由於實際的裁減過程中會遇到各種各樣的問題,有些方面牽涉太廣,以至沒有辦法單獨說明,所以接下來是一些可能會遇到的問題說明:
1、nvidia的驅動需要先在發行版上解開,再執行make && make install > install,然後修改install中的目標路徑以將相關檔安裝到DOM上,比如cp libGL.so /usr/lib改為cp libGL.so /mnt/dom/usr/lib。具體操作就不列舉了。
2、busybox的mount有問題,不能mount -o loop,所以cramfs的檔需要用發行版的mount,所以在dom的/mnt/cramfs目錄下有一個mount,而/bin也有一個mount
3、為了便於調試,在dom中加入了telnet server和ftp client,分別使用的是utelnetd和cmdftp,出處可以通過google搜索
4、grub的安裝使用grub-install即可
5、由於firebird等模組至少需要一個root用戶,而busybox缺省是沒有用戶的,所以需要在/etc下複製兩個檔:shadow和passwd
6、dhcp client使用的是udhcpc
7、字體主要和以下目錄有關:/usr/lib/gconv、/usr/lib/locale、/usr/X11R6/lib/X11/font和/usr/X11R6/lib/X11/locale(限於redhat,其他發行版會有一些差異,但具體內容是一樣的)
8、硬體自檢使用的是hwsetup,並對源代碼做過一些修改,只保留了audio和network card的檢測,在附件裏有原始和修改過的兩個版本,可以對比參考
9、web site功能是用kylix自己實現的,沒有使用apache
10、由於dom的空間不足以攤平所有檔,所以/usr下面的檔全部都是以一個cramfs檔的格式出現的,參看後面的檔列表。

七、DOM的最後安裝和打包:
cramfs文件的創建:
1、確定目標分區的可運行
2、確定/mnt/dom/usr/目錄下的檔完整性
3、mkcramfs /mnt/usr.cramfs /mnt/dom/usr # make a cramfs file of usr path
4、保存/mnt/dom下的完整列表,以備將來的修改
5、rm /mnt/dom/usr/* -rf
6、mkdir /mnt/dom/mnt/cramfs
7、cp /mnt/usr.cramfs /mnt/dom/mnt/cramfs
8、cp /bin/mount /mnt/dom/mnt/cramfs -arf
9、add /mnt/dom/etc/init.d/rcS:/mnt/cramfs/mount -o loop -t cramfs /mnt/cramfs/usr.cramfs /usr

現在,/mnt/dom目錄下就已經是一個除了grub全部都是完整的DOM鏡像了。那麼最後要將這個鏡像導入真實的DOM之中:
mkdir /mnt/realdom
mount /dev/hdc1 /mnt/realdom # assume /dev/hdc1 is real dom
cp /mnt/dom/* /mnt/realdom/ -arf
sync
此時DOM中已經有了一個完整的鏡像,但還沒有grub,那麼執行:
grub-install /dev/hdc1
重新啟動,並在BOIS中選擇真正的DOM,確認DOM的啟動沒有問題。重新切換到發行版,開始做DOM的鏡像檔:
dd if=/dev/hdc of=domfs # domfs is image of dom
保存好這個名字為domfs的鏡像檔,這就是一個可安裝的包,安裝到其他DOM中時,輸入:
dd if=domfs of=/dev/hdc
到目前為止,所有的流程都走了一遍,剩下的就是不斷的實踐和驗證了。

後記:
經過一次完整的裁減過程,很自然的對Linux的整體結構和方式有了很清晰的瞭解,雖然不能對kernel有深入瞭解,但是起碼為以後kernel方面的學習打下了很好的基礎。由於牽涉方面比較多和雜,有些部分只能是實踐過後才能知道其中的訣竅,當然大體的過程是一樣的。

2004-06-01
cyantree


附錄:
DOM文件列表:


**************************************************************************************

第一章 前言
目的
本文的目的,是講述嵌入式Linux系統的建立、開發的一般過程。製作一個小型的Linux的系統,可以移植至其他硬碟、軟碟、優盤、flash rom……

關於作者
九賤,E名kendo,喜歡網路入侵技術、防火牆、入侵檢測技術及網路技術,對Linux也頗感興趣,想認識有共同愛好的朋友。最近閒暇,把一些學過的東西寫下來,總結總結,以作備忘這需。已完成的有《網路入侵檢測設計與Snort2.2源碼分析》和這篇《我也來學做嵌入式Linux》。正在進行中的有《Windows防火牆技術實現大全》和《Linux防火牆實現及源碼分析》。大家可以在CU上,或者是到我的小站www.skynet.org.cn上與我交流

做一個嵌入式Linux系統究竟要做哪些工作
做一個嵌入式Linux系統究竟需要做哪些工作?也就是本文究竟要講述哪些內容?我先介紹一個脈絡,可以做為我們後面工作的一個總的提綱:
第一步、建立交叉編譯環境
沒有交叉開發經驗的讀者,可能一時很難接受這個概念。首先,要明白兩個概念:一般我們工作的機器,稱為開發機、主機;我們製作好的系統將要放到某台機器,如手機或另一台PC機,這台機我們稱為目標主機。
我們一般開發機上已經有一套開發工具,我們稱之為原生開發套件,我們一般就是用它們來寫程式,那麼,那什麼又是交叉編譯環境呢?其實一點也不神秘,也就是在開發機上再安裝一套開發工具,這套開發工具編譯出來的程式,如內核、系統工作或者我們自己的程式,是放在目標主機上運行的。
那麼或許有初學者會問,直接用原生開發工具為目標主機編譯程序不就完了?至少我當初是這麼想的。一般來說,我們的開發機都是X86平臺,原生開發套件開發的工具,也針對X86平臺,而我們的目標主機可能是PowerPC、IXP、MIPS……所以,我們的交叉編譯環境是針對某一類具體平臺的。
一般來講,交叉開發環境需要二進位工具程式、編譯器、C程式庫,嵌入式開發常用的這三類軟體是:
Binutils
Gcc
uClibc
當然,GNU包含的工具套件不僅於此,你還要以根據實際需要,進行選擇

第二步、編譯內核
開發工具是針對某一類硬體平臺,內核同樣也是。這一步,我們需要用第一步中建立的工具,對內核進行編譯,對於有內核編譯經驗的人來說,這是非常簡單的;

第三步、建立根檔系統
也就是建立我們平常看到的bin、dev、proc……這一大堆目錄,以及一些必備的檔;另外,我們還需要為我們的目標系統安裝一些常用的工具軟體,如ls、ifconfig……當然,一個辦法是找到這些工具的源代碼,用第一步建立的交叉編譯工具來編譯,但是這些軟體一是數量多,二是某些體積較大,不適合嵌入式系統,這一步,我們一般都是用busybox來完成的,包括系統引導軟體init;
最後,我們為系統還需要建立初始化的引導檔,如inittab……

第四步、啟動系統
在這一步,我們把建立好的目標、檔、程式、內核及模組全部拷貝到目的機記憶體上,如硬碟。然後為系統安裝bootloader,對於嵌入式系統,有許多引導程式可供我們使用。不過它們許多都有硬體平臺的限制。當然,如果你是工作在X86,可以直接用lilo來引導,事實上,本文就是採用的lilo。
做到這一步,將目標存儲設備掛上目的機,如果順利,就可以啟動系統了。
當然,針對某些特別的平臺,不能像硬碟這樣拷貝了,需要讀卡器、燒錄……但是基本的方法是相通的!

第五步、優化和個性化系統
通過前四步,我們已經得到了一個可以正常工作的系統。在這一步裏,就是發揮你想像的時候了……


本文的工作環境
專案根目錄/home/kendo/project ------>;我將它指定至PATH:$PRJROOT
子目錄及說明
目錄 內容
bootloader 目標板的引導載入程式,如lilo等
build-tools 建立交叉編譯平臺的工具源碼
debug 調試工具及所有相關包
doc 項目中用到的所有文檔
images 編譯好的內核映射,以及根檔系統
kernel 各個版本的Linux內核源碼
rootfs 製作好的根檔系統
sysapps 目標板將要用到的系統應用系統,比如thttpd,udhcpd等
tmp 存放暫存檔案
tools 編譯好的跨平臺開發工具鏈以及C程式庫


工作的腳本
#!/usr/bin

export PROJECT=skynet
export PRJROOT=/home/${PROJECT}
export TARGET=i386-linux
export PREFIX=${PRJROOT}/tools
export TARGET_PREFIX=${PREFIX}/${TARGET}
export PATH=${PREFIX}/bin:/bin:/sbin:/usr/bin:/usr/sbin

cd $PRJROOT


第二章 建立交叉編譯環境
在CU中發表的另一篇同名的貼子裏,我講述了一個全手工創建交叉編譯環境的方法。目前,創建交叉編譯環境,包括建立根檔,一般來講,有兩種方法:
手功創建
可以得到最大程式的個性化定制,缺點是過程繁雜,特別是極易出錯,注意這個“極”字,包括有經驗的開發人員;
自動創建
無它,方便而。

因為前一篇文章中,已經講述了全手工創建交叉編譯環境的一般性方法,本文就不打算再重複這個步驟了,感興趣的朋友,可以再去搜索那篇貼子,提醒一點的就是,在準備工具鏈的時候,要注意各個工具版本之間的搭配、每個工具需要哪些補丁,我建議你在google上針對這兩項搜索一下,準備一個清單,否則……
本章要講述的是自動創建交叉編譯環境的方法。目標,針對商業硬體平臺,廠家都會為你提供一個開發包,我用過XX廠家的IXP425和MIPS的,非常地方便,記得我第一次接觸嵌入式開發,拿著這個開發包自動化創建交叉編譯環境、編譯內核、建立根檔系統、創建Ram Disk,我反復做了三四次,結果還不知道自己究竟做了些什麼,呵呵,夠傻吧……
所以,建議沒有這方面經驗的讀者,還是首先嘗試一下手工創建的方法吧,而本章接下來的內容,是送給曾經被它深深傷害而不想再次去親歷這項工作而又想提高交率而又在通用平臺上工作沒有商業開發包的朋友。

建立交叉開發工具鏈
準備工具:
buildroot-0.9.27.tar.tar
只需要一個軟體?對,其他的不用準備了,buildroot事實上是一個腳本與補丁的集合,其他需要用到的軟體,如gcc、uClibc,你只需在buildroot中指明相應的版本,它會自動去給你下載。
事實上,buildroot到網上去下載所需的所有工作是需要時間的,除非你的帶寬足夠,否則下載軟體時間或許會占去80%,而我在做這項工作之間,所需的工作鏈全部都在我本地硬碟上,我解壓開buildroot後,新建dl檔夾,將所有工具源碼的壓縮包拷貝進去,呵呵,buildroot就不用去網上下載了。

我的軟體清單:
Linux-libc-headers-2.4.27.tar.bz2
Gcc-3.3.4.tar.bz2
binutils 2.15.91.0.2.tar.bz2
uClibc 0.9.27.tar.bz2
genext2fs_1.3.orig.tar.gz
ccache-2.3.tar.gz

將它拷貝到${PRJROOT}/build-tools下,解壓
[root@skynet build-tools]# tar jxvf buildroot-0.9.27.tar.tar
[root@skynet build-tools]#cd buildroot
配置它:
[root@skynet build-tools]#make menuconfig
Target Architecture (i386) --->; 選擇硬體平臺,我的是i386
Build options --->; 編譯選項
這個選項下重要的是(${PRJROOT}/tools) Toolchain and header file location?編譯好的工具鏈放在哪兒?
如果你像我一樣,所有工具包都在本地,不需它到網上自動下載,可以把wget command選項清空;
Toolchain Options --->; 工具鏈選項
--- Kernel Header Options 頭檔它會自動去下載,不過應該保證與你將要用的內核是同一個版本;
[] Use the daily snapshot of uClibc? 使用最近的uClibc的snapshot
Binutils Version (binutils 2.15.91.0.2) --->; Binutils的版本
GCC compiler Version (gcc 3.4.2) --->; gcc 版本

  • Build/install c++ compiler and libstdc++?
    [ ] Build/install java compiler and libgcj? 支援的語言,我沒有選擇java
    [ ] Enable ccache support? 啟用ccache的支援,它用於編譯時頭檔的緩存處理,用它來編譯程序,第一次會有點慢,但是以後的速度可就很理想了,呵呵……
    --- Gdb Options 根據你的需要,選擇gdb的支援

    Package Selection for the target --->;
    這一項我沒有選擇任意一項,因為我打算根檔系統及busybox 等工具鏈創建成工,手工來做。
    Target Options --->; 檔系統類型,根據實際需要選,我用的ext2;

    配置完成後,編譯它:
    [root@skynet build-tools]#make

    這一項工作是非常花時間的,我的工具包全部在本地,也花去我一小時十三分的時間,如果全要下載,我估計網速正常也要多花一兩個鐘頭。

    經過漫長的等待(事實上並不漫長,去打了幾把遊戲,很快過去了):
    ……
    make[1]: Leaving directory `/home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3'
    touch -c /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs
    #-@find /home/skynet/build-tools/buildroot/build_i386/root/lib -type f -name \*.so\* | xargs /home/skynet/tools/bin/i386-linux-uclibc-strip --remove-section=.comment --remove-section=.note --strip-unneeded 2>;/dev/null || true;
    /home/skynet/build-tools/buildroot/build_i386/genext2fs-1.3/genext2fs -i 503 -b 1056 \
    -d /home/skynet/build-tools/buildroot/build_i386/root -q -D target/default/device_table.txt /home/skynet/build-tools/buildroot/root_fs_i386.ext2

    大功告成!!!

    清點戰利品
    讓我來看看它究竟做了哪些事情吧:
    [root@skynet skynet]# cd tools
    [root@skynet tools]# ls
    bin bin-ccache i386-linux i386-linux-uclibc include info lib libex!ec man usr

    bin:所有的編譯工具,如gcc,都在這兒了,只是加了些指定的首碼;
    bin-ccache:如果在Toolchain optaion中沒有選擇對ccache的支持,就沒有這一項了;
    i386-linux:鏈結檔;實際指向include
    i386-linux-uclibc:uclibc的相關工具;
    include:供交叉開發工具使用的頭文件;
    info:gcc 的info文件;
    lib:供交叉開發工具使用的程式庫文件;
    ……

    現在可以把編譯工具所在目錄XXX/bin添加至PATH了

    測試工具鏈
    如果你現在寫一個程式,用i386-linux-gcc來編譯,運行的程式會告訴你:
    ./test: linked against GNU libc
    因為程式運行庫會尋到默認的/lib:/usr/lib上面去,而我們目前的uclibc的庫並不在那裏(雖然對於目的機來講,這是沒有錯的),所以,也只能暫時靜態編譯,試試它能否工作了。當然,你也可以在建好根檔系統後,試試用chroot……

    第三章 編譯內核
    本章的工作,是為目的機建立一個合適的內核,對於建立內核,我想有兩點值得考慮的:
    1、功能上的選擇,應該能夠滿足需要的情況下,儘量地小;
    2、小不是最終目的,穩定才是;

    所以,最好編譯內核前有一份目的機硬體平臺清單以及所需功能清單,這樣,才能更合理地裁減內核。

    準備工具
    Linux內核源碼,我選用的是Linux-2.4.27.tar.bz2

    編譯內核
    將Linux-2.4.27.tar.bz2拷貝至${PRJROOT}/kernel,解壓
    #cd linux-2.4.27
    //配置
    # make ARCH=i386 CROSS_COMPILE=i386-linux- menuconfig
    //建立源碼的依存關係
    # make ARCH=i386 CROSS_COMPILE=i386-linux- clean dep
    //建立內核映射
    # make ARCH=i386 CROSS_COMPILE=i386-linux- bzImage
    ARCH指明了硬體平臺,CROSS_COMPILE指明了這是交叉編譯,且編譯器的名稱為i386-linux-XXX,這裏沒有為編譯器指明路徑,是因為我前面已將其加入至環境變數PATH。

    又是一個漫長的等待……
    OK,編譯完成,673K,稍微大了點,要移到其他平臺,或許得想辦法做到512以下才好,回頭來想辦法做這個工作。

    安裝內核
    內核編譯好後,將內核及配置檔拷貝至${PRJROOT}/images下。
    # cp arch/i386/boot/bzImage ${PRJROOT}/images/bzImage-2.4.27-rmk5
    # cp vmlinux ${PRJROOT}/images/vmlinux-2.4.27-rmk5
    # cp System.map ${PRJROOT}/images/System-2.4.27-rmk5
    # cp .config ${PRJROOT}/images/2.4.27-rmk5

    我採用了尾碼名的方式重命名,以便管理多個不同版本的內核,當然,你也可以不用這樣,單獨為每個版本的內核在images下新建對應檔夾也是可行的。

    安裝內核模組
    完整內核的編譯後,剩下的工作就是建立及安裝模組了,因為我的內核並沒有選擇模組的支援(這樣擴展性差了一點,但是對於我的系統來說,功能基本上定死了,這樣影響也不太大),所以,剩下的步驟也省去了,如果你還需要模組的支援,應該:
    //建立模組
    #make ARCH=i386 CROSS_COMPILE=i386-linux- modules
    //安裝內核模組至${PRJROOT}/images
    #make ARCH=i386 CROSS_COMPILE= i386-linux- \
    >;INSTALL_MOD_PATH=${PRJROOT}/images/modules-2.4.18-rmk5 \
    >;modules_install

    最後一步是為模組建立依存關係,不能使用原生的depmod來建立,而需要使用交叉編譯工具。需要用到busybox中的depmod.pl腳本,很可惜,我在busybox1.0.0中,並沒有找到這個腳本,所以,還是借用了busybox0.63中scripts中的depmod.pl。
    將depmod.pl拷貝至${PREFIX}/bin目錄中,也就是交叉編譯工具鏈的bin目錄。
    #depmod.pl \
    >;-k ./vmlinux –F ./System.map \
    >;-b ${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules >; \
    >;${PRJROOT}/images/modules-2.4.27-rmk5/lib/modules/2.4.27-rmk5/modules.dep

    注:後面討論移植內核和模組內容時,我只會提到內核的拷貝,因為我的系統並沒有模組的支援。如果你需要使用模組,只需按相同方法將其拷貝至相應目錄即可。

    附,內核編譯清單
    附,內核選擇:
    內核編譯記錄:
    Code maturity level options 不選
    Loadable module support 不選
    Processor type and features 根據實際,選擇處理器類型
    General setup --->;

  • Networking support
  • PCI support
    (Any) PCI access mode
  • PCI device name database
  • System V IPC
  • Sysctl support
    (ELF) Kernel core (/proc/kcore) format
  • Kernel support for ELF binaries
  • Power Management support

    Memory Technology Devices (MTD) --->; MTD設備,我用CF卡,不選

    Parallel port support --->; 不選
    Plug and Play configuration --->; 我的系統用不著即插即用,不選

    Block devices --->;

  • Loopback device support
  • RAM disk support
    (4096) Default RAM disk size (NEW)
  • Initial RAM disk (initrd) support

    Multi-device support (RAID and LVM) --->; 不選

    Networking options --->; 基本上都選了

    ATA/IDE/MFM/RLL support --->; 用了默認的

    Telephony Support --->; 不選

    SCSI support --->; 不選

    Fusion MPT device support --->; 不選

    I2O device support --->; 不選

    Network device support --->; 根據實際情況選擇

    Amateur Radio support --->; 不選

    IrDA (infrared) support --->; 不選

    ISDN subsystem --->; 不選

    Old CD-ROM drivers (not SCSI, not IDE) --->; 不選

    Input core support --->; 不選

    Character devices --->;

  • Virtual terminal
  • Support for console on virtual terminal
  • Standard/generic (8250/16550 and compatible UARTs) serial support
  • Support for console on serial port

    Multimedia devices --->; 不選

    File systems --->;

  • Kernel automounter version 4 support (also supports v3)
  • Virtual memory file system support (former shm fs)
  • /proc file system support
  • Second extended fs support

    Console drivers --->;

  • VGA text console 調試時接顯示器用

    剩下三個都不要
    Sound --->;
    USB support --->;
    Kernel hacking --->;

    第四章 建立根檔系統
    1、建立目錄
    構建工作空間時,rootfs檔夾用來存放根檔系統,
    #cd rootfs
    根據根檔系統的基本結構,建立各個對應的目錄:
    # mkdir bin dev etc lib proc sbin tmp usr var root home
    # chmod 1777 tmp
    # mkdir usr/bin usr/lib usr/sbin
    # ls
    dev etc lib proc sbin tmp usr var
    # mkdir var/lib var/lock var/log var/run var/tmp
    # chmod 1777 var/tmp

    對於單用戶系統來說,root和home並不是必須的。
    準備好根檔系統的骨架後,把前面建立的檔安裝到對應的目錄中去。
    2、拷貝程式庫
    把uclibc的庫檔拷貝到剛才建立的lib文件夾中:
    # cd ${PREFIX}/lib
    [root@skynet lib]# cp *-*.so ${PRJROOT}/rootfs/lib
    [root@skynet lib]# cp -d *.so.[*0-9] ${PRJROOT}/rootfs/lib

    3、 拷貝內核映射和內核模組
    因為沒有模組,所以拷貝模組就省了,
    新建boot目錄,把剛才建立好的內核拷貝過來
    # cd /home/kendo/control-project/daq-module/rootfs/
    # mkdir boot
    # cd ${PRJROOT}/images
    # cp bzImages-2.4.18-rmk5 /home/kendo/control-project/daq-module/rootfs/boot

    4、 建立/dev下邊的設備檔
    在linux中,所有的的設備檔都存放在/dev中,使用mknod命令創建基本的設備檔。
    mknod命令需要root許可權,不過偶本身就是用的root用戶,本來是新建了一個用戶專門用於嵌入式製作的,不過後來忘記用了……
    # mknod -m 600 mem c 1 1
    # mknod -m 666 null c 1 3
    # mknod -m 666 zero c 1 5
    # mknod -m 644 random c 1 8
    # mknod -m 600 tty0 c 4 0
    # mknod -m 600 tty1 c 4 1
    # mknod -m 600 ttyS0 c 4 64
    # mknod -m 666 tty c 5 0
    # mknod -m 600 console c 5 1
    基本的設備檔建立好後,再創建必要的符號鏈結:
    # ln -s /proc/self/fd fd
    # ln -s fd/0 stdin
    # ln -s fd/1 stdout
    # ln -s fd/2 stderr
    # ls
    console fd mem null random stderr stdin stdout tty tty0 tty1 ttyS0 zero

    設備檔也可以不用手動創建,聽說RedHat /dev下的腳本MAKEDEV 可以實現這一功能,不過沒有試過……

    基本上差不多了,不過打算用硬碟/CF卡來做存儲設備,還需要為它們建立相關檔,因為我的CF在目的機器上是CF-to-IDE,可以把它們等同來對待,先看看Redhat 下邊had的相關屬性:
    # ls -l /dev/hda
    brw-rw---- 1 root disk 3, 0 Jan 30 2003 /dev/hda
    # ls -l /dev/hda1
    brw-rw---- 1 root disk 3, 1 Jan 30 2003 /dev/hda1
    對比一下,可以看出,had類型是b,即塊設備,主編號為3,次編號從0遞增,根限位是
    rw-rw----,即660,所以:
    # mknod -m 660 hda b 3 0
    # mknod -m 660 hda1 b 3 1
    # mknod -m 660 hda2 b 3 2
    # mknod -m 660 hda3 b 3 3


    5、添加基本的應用程式
    未來系統的應用程式,基本上可以分為三類:
     基本系統工具,如ls、ifconfig這些……
     一些服務程式,管理工具,如WEB、Telnet……
     自己開發的應用程式

    這裏先添加基本的系統工具,有想過把這些工具的代碼下載下來交叉編譯,不過實在是麻煩,用BusyBox,又精簡又好用……
    將busybox-1.00.tar.gz下載至sysapps目錄下,解壓:
    #tar zxvf busybox-1.00.tar.gz
    #cd busybox-1.00
    //進入配置功能表
    #make TARGET_ARCH=i386 CROSS=i386-linux- PREFIX=${PRJROOT}/rootfs menuconfig
    //建立依存關係
    #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs dep
    //編譯
    #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs
    //安裝
    #make TARGET_ARCH=i386 CROSS= i386-linux- PREFIX=${PRJROOT}/rootfs install

    # cd ${PRJROOT}/rootfs/bin
    # ls
    addgroup busybox chown delgroup echo kill ls mv ping rm sleep
    adduser chgrp cp deluser grep ln mkdir netstat ps rmdir umount
    ash chmod date dmesg hostname login mount pidof pwd sh vi
    一下子多了這麼多命令……
    配置busybox的說明:
    A、如果編譯時選擇了:
    Runtime SUID/SGID configuration via /etc/busybox.conf
    系統每次運行命令時,都會出現“Using fallback suid method ”
    可以將它去掉,不過我還是在/etc為其建了一個檔busybox.conf搞定;
    B、

  • Do you want to build BusyBox with a Cross Compiler? (i386-linux-gcc) Cross Compiler prefix
    這個指明交叉編譯器名稱(其實在編譯時的命令行已指定過了……)
    C、安裝選項下的(${PRJROOT}/rootfs) BusyBox installation prefix,這個指明了編譯好後的工具的安裝目錄。
    D、靜態編譯好還是動態編譯好?即是否選擇
    [ ] Build BusyBox as a static binary (no shared libs)
    動態編譯的最大好處是節省了寶貴空間,一般來說都是用動態編譯,不過我以前動態編譯出過問題(其實是庫的問題,不關busybox的事),出於慣性,我選擇了靜態編譯,為此多付出了107KB的空間。
    E、其他命令,根據需要,自行權衡。


    6、系統初始化檔
    內核啟動時,最後一個初始化動作就是啟動init程式,當然,大多數發行套件的Linux都使用了與System V init相仿的init,可以在網上下載System V init套件,下載下來交叉編譯。另外,我也找到一篇寫得非常不錯的講解如何編寫初始化文件的文件,bsd-init,回頭附在後面。不過,對於嵌入式系統來講,BusyBox init可能更為合適,在第6步中選擇命令的時候,應該把init編譯進去。
    #cd ${PRJROOT}/rootfs/etc
    #vi inittab
    我的inittal文件如下:
    #指定初始化檔
    ::sysinit:/etc/init.d/rcS
    #打開一個串口,串列傳輸速率為9600
    ::respawn:/sbin/getty 9600 ttyS0
    #啟動時執行的shell
    ::respawn:/bin/sh
    #重啟時動作
    ::restart:/sbin/init
    #關機時動作,卸載所有檔系統
    ::shutdown:/bin/umount -a –r

    保存退出;

    再來編寫rcS腳本:
    #mkdir ${PRJROOT}/rootfs/etc/init.d
    #cd ${PRJROOT}/rootfs/etc/init.d
    #vi rcS
    我的腳本如下:
    #!/bin/sh

    #Set Path
    PATH=/sbin:/bin
    export PATH

    syslogd -m 60
    klogd

    #install /proc
    mount -n -t proc none /proc

    #reinstall root file system by read/write mode(need: /etc/fstab)
    mount -n -o remount,rw /

    #reinstall /proc
    mount -n -o remount,rw -t proc none /proc

    #set lo ip address
    ifconfig lo 127.0.0.1

    #set eth0 ip address
    #當然,這樣子做只是權宜之計,最後做的應該是在這一步引導網路啟動腳本,像RedHat
    #那樣,自動讀取所有指定的配置檔來啟動
    ifconfig eth0 192.168.0.68 netmask 255.255.255.0

    #set route
    #同樣的,最終這裏應該是運行啟動路由的腳本,讀取路由配置檔
    route add default gw 192.168.0.1

    #還差一個運行服務程式的腳本,哪位元有現成的麼?
    #網卡/路由/服務這三步,事實上可以合在一步,在rcS這一步中,做一個迴圈,運行指定啟動目錄下的所有腳,先將就著這麼做吧,確保系統能夠正常啟動了,再來寫這個腳本。

    #set hostname
    hostname MyLinux

    保存退出。

    編寫fstab檔
    #vi fstab
    我的fstab很簡單:
    /dev/hda1 / ext2 defaults 1 1
    none /proc proc defaults 0 0

    第五章 讓MyLinux能夠啟動
    前一章,我們把編譯好的內核、應用程式、配置檔都拷貝至rootfs目錄對應的子目錄中去了,這一步,就是把這些檔移植至目的機的記憶體。這裏,我是先另外拿一塊硬碟,掛在我的開發機上做的測試,因為我的本本用來寫文檔,PC機用來做開發機,已經沒有另外的機器了……但是本章只是講述一個一般性的過程,並不影響你直接在目標主機上的工作。
    因為以後目的機識別硬碟序號都是hda,而我現在直接掛上去,則會是hdb、hdc……這樣,安裝lilo時有點麻煩(雖然也可以實現)。所以我想了另一個辦法:
     把新硬碟掛在IDE0的primary上,進入linux後,會被認為是had;
     原來主機的裝Redhat的硬碟,我將它從IDE0的primary上變到了IDE1 的primary,因為它的lilo早已裝好,基本上不影響系統的使用;

    分區和格式化
    BIOS中改為從第二個硬碟啟動;也就是從我原來開發機啟動,新的硬碟被識別成了had。
    #fdisk /dev/hda
    用d參數刪除已存在的所有分區
    用n參數新建一個分區,也是就/dev/hda1
    格式化
    #mkfs.ext2 /dev/hda1

    安裝bootloader
    因為我是X86平臺,所以直接用了lilo,如果你是其這平臺,當然,有許多優秀的bootloader供你選擇,你只需查看其相應的說明就可以了。
    編譯lilo配置檔,我的配置檔案名為target.lilo.conf,置於${PRJROOT}/rootfs/etc目錄。內容如下所示:
    boot=/dev/hda
    disk=/dev/hda
    bios=0x80
    image=/boot/bzImage-2.4.18-rmk5
    label=Linux
    root=/dev/hda1
    append="root=/dev/hda1"
    read-only

    //新建文件夾,為mount做新準備
    #mkdir /mnt/cf
    //把目標硬碟mount上來
    #mount –t ext2 /dev/hdc1 /mnt/cf
    回到rootfs
    #cd ${PRJROOT}/rootfs
    拷貝所有檔至目標硬碟
    #cp –r * /mnt/cf

    這樣,我們所有的檔都被安裝至目標硬碟了,當然,它還不能引導,因為沒有bootloader。使用如下命令:
    # lilo -r /mnt/cf -C etc/target.lilo.conf
    Warning: LBA32 addressing assumed
    Added Linux *
    -r :改變根目標為/mnt/cf ,這樣配置檔其實就是/mnt/cf/etc/target.lilo.conf,也就是我們先前建立的文件。
    當然,完成這一步,需要lilo22.3及以後版本,如果你的版本太舊,比如Redhat9.0自帶的,就會出現下面的資訊:
    #lilo –r /mnt/cf –C etc/target.lilo.conf
    Fatal: open /boot/boot.b: No such file or directory
    這時,你需要升級你的lilo,或者重新安裝一個。

    啟動系統
    #umount /mnt/cf
    #reboot

    將BIOS改為從IDE0啟動,也就是目標硬碟。如果一切順利,你將順利進入一個屬於你的系統。

    回頭再來看看我們的工作空間吧
    [root@skynet lib]# df /dev/hda1
    Filesystem 1K-blocks Used Available Use% Mounted on
    /dev/hda1 3953036 1628 3750600 1% /mnt/cf

    總共花去了我1628KB的空間,看來是沒有辦法放到軟碟裏邊去了^o^,不過一味求小,並不是我的目標。

    [root@skynet skynet]# ls ${PRJROOT}
    bootloader build-tools debug doc images kernel rootfs sysapps tmp tools
    這幾個目錄中的檔,呵呵,與本文一開頭規劃的一樣

    [root@skynet skynet]# ls build-tools/
    buildroot buildroot-0.9.27.tar.tar
    包含了buildroot源碼及壓縮包,事實上buildroot下邊還包括了GNU其他工具的源碼、編譯檔等諸多內容,是我們最重要的一個檔夾,不過到現在它已經沒有多大用處了,如果你喜歡,可以將它刪除掉(不建議)。

    [root@skynet skynet]# ls images
    2.4.18-rmk5 bzImage-2.4.18-rmk5 System-2.4.18-rmk5 vmlinux-2.4.18-rmk5
    內核映射及配置檔等,如果你有模組,因為還有相應的目錄

    [root@skynet skynet]# ls kernel/
    linux-2.4.27 linux-2.4.27.tar.bz2
    內核源碼及壓縮包

    [root@skynet skynet]# ls rootfs/
    bin boot dev etc home lib linuxrc proc root sbin tmp usr var
    製作好的根檔系統,重中之重,注意備份……

    [root@skynet skynet]# ls sysapps/
    busybox-1.00 busybox-1.00.tar.gz
    busybox-1.00源碼包,或許你還要繼續添加/刪除一些命令……

    [root@skynet skynet]# ls tools
    bin i386-linux i386-linux-uclibc include info lib man
    這個也很重要,我們製作好的交叉開發工具鏈。如果你要繼續開發程式,這個目錄重要性就很高了。

    其他目錄暫時是空的。


    第六章 完善MyLinux
    關於進一步的調試,你可以在開發機上使用chroot /mnt/cf /bin/sh這樣的命令,以使我們在目標根檔系統上工作。

    支援多用戶
    因為我在編譯busybox時,已經將它的多用戶那一大堆命令編譯了進來。現在關鍵是的要為其建立相應的檔;
    進入原來的開發機,進入rootfs目錄,切換根目錄
    #chroot rootfs/ /bin/sh
    A、 建立/etc/passwd檔,我的檔內容如下:
    root:x:0:0:root:/root:/bin/bash
    B、 建立/etc/group檔,我的檔內容如下:
    root:x:0:
    bin:x:1:
    sys:x:2:
    kmem:x:3:
    tty:x:4:
    tape:x:5:
    daemon:x:6:
    disk:x:7:
    C、 為root建立密碼
    #passwd root

    試試用addgroup/addusr……這堆命令。然後重啟,從目標硬碟上啟動;從console口,9600登陸試試(因為我在inittab中啟用了ttyS0,我未來的目的機,是沒有顯卡的,需要從console口或SSH進去管理)
    MyLinux login: root
    Password:

    BusyBox v1.00 (2004.10.10-04:43+0000) Built-in shell (ash)
    Enter 'help' for a list of built-in commands.

    ~ #
    成功了……

    增加WEB Server
    Busybox裏邊有httpd選項,不過我編譯時並沒有選擇,所以還是自己來安裝。我使用的軟體是thttpd-2.25b.tar.gz,將它移至sysapps目錄下。
    [root@skynet sysapps]# tar zxvf thttpd-2.25b.tar.gz
    [root@skynet sysapps]# cd thttpd-2.25b
    //配置
    [root@skynet thttpd-2.25b]# CC=i386-linux-gcc ./configure --host=$TARGET
    ……
    i386-linux-gcc -static htpasswd.o -o htpasswd -lcrypt
    make[1]: warning: Clock skew detected. Your build may be incomplete.
    make[1]: Leaving directory `/home/skynet/sysapps/thttpd-2.25b/extras'
    //拷貝至根檔目錄
    [root@skynet thttpd-2.25b]# cp thttpd ${PRJROOT}/rootfs/usr/sbin
    //trip處理
    [root@skynet thttpd-2.25b]# i386-linux-strip ${PRJROOT}/rootfs/usr/sbin/thttpd

    剩下的,就發揮各人的想像吧……


    獨孤九賤 2005-11-1 02:34

    繼續補完

    不好意思,最近工作太忙,好久沒有來搞這個東東了,加之心愛的手機丟了,心情又不太好,不過一切都過去了,繼續來將它補充完整。

    修改啟動腳本
    在前面寫rcS啟動腳本中。當時只是為了系統能夠正常地啟動,在啟動網卡/路由/服務等時,有如下語句:
    ——————————————————————————————————————————————
    #set lo ip address
    ifconfig lo 127.0.0.1

    #set eth0 ip address
    #當然,這樣子做只是權宜之計,最後做的應該是在這一步引導網路啟動腳本,像RedHat
    #那樣,自動讀取所有指定的配置檔來啟動
    ifconfig eth0 192.168.0.68 netmask 255.255.255.0

    #set route
    #同樣的,最終這裏應該是運行啟動路由的腳本,讀取路由配置檔
    route add default gw 192.168.0.1
    ……
    ———————————————————————————————————————————————
    這樣配置的最大壞處就是不能根據配置檔自定義,每次開機都定死了,現在來修改它,將這段語句刪除之,換成如下語句:
    for i in /etc/start/S??* ;do
    # Ignore dangling symlinks (if any).
    [ ! -f "$i" ] && continue

    echo "Running $i ."
    case "$i" in
    *.sh)
    # Source shell script for speed.
    (
    trap - INT QUIT TSTP
    set start
    . $i
    )
    ;;
    *)
    # No sh extension, so fork subprocess.
    $i start
    ;;
    esac
    echo "Done $i ."
    echo
    done
    解釋一下,這段語句的作用,就是啟動/etc/start/目錄下,所有以S開頭的腳本檔,可以啟動兩類,以sh結尾或沒有 sh尾碼的。
    這樣,我們在/etc/目錄下再新建一目錄start/,這裏面就是我們啟動時需要的腳本的。先來啟動網卡。

    修改網卡配置檔
    我是根據Red hat的作法,把網卡配置放在/etc/sysconfig/network-scripts目錄下,類似於ifcfg-ethXX這樣子,它們的語法是:
    DEVICE=eth0
    BOOTPROTO=static
    BROADCAST=88.88.88.255
    IPADDR=88.88.88.44
    NETMASK=255.255.255.0
    NETWORK=88.88.88.0
    ONBOOT=yes
    好,建立這些目錄和檔,我共有兩個檔ifcfg-ethXX。回到/etc/start目錄,建立網卡的啟動腳本S01interface:
    #!/bin/sh

    . /etc/sysconfig/network
    #enable ip_forword
    echo >1 /proc/sys/net/ipv4/ip_forward

    #enable syn_cookie
    echo >1 /proc/sys/net/ipv4/tcp_syncookies

    #enable loopback interface
    /sbin/ifconfig lo 127.0.0.1

    #eanble ethernet interface
    /usr/sbin/bootife

    #set hostname
    if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]
    then
    HOSTNAME=localhost
    fi

    /bin/hostname ${HOSTNAME}

    請注意這個腳本檔,有兩個地方:
    1、包含了另一個配置檔/etc/sysconfig/network,在這裏,我也是照抄了redhat,我的/etc/sysconfig/network這個檔的內容如下:
    NETWORKING=yes
    HOSTNAME=skynet
    GATEWAY=88.88.88.2
    2、在啟動網卡時,我使用了
    #eanble ethernet interface
    /usr/sbin/bootife
    bootife是我自己寫的一個C程式,作用是讀取/etc/sysconfig/network-scripts/下面的ifcfg-ethXX檔,並配置之,本來這裏就該用shell來完成更合適一點,無奈,偶shell功底實在差了一點(剛學幾天),就是想從Redhat中照抄過來,反復試了幾次也沒有成功。所以被逼無奈用C來完成之,後面我會附上我的C的源碼,也希望哪位大哥能夠寫一段Shell的程式代替它,放上來大家共用之。

    修改路由啟動檔
    同樣的,我在/etc/start下,建立新腳本S02route.sh,它的作用是啟動所有配置的靜態路由:
    #!/bin/bash

    . /etc/sysconfig/network
    # Add non interface-specific static-routes.

    if [ -f /etc/sysconfig/static-routes ]
    then
    grep "eth*" /etc/sysconfig/static-routes | while read ignore args ; do
    # echo "/sbin/route add -"$args
    /sbin/route add -$args
    done
    fi

    #Add defalut gw
    /sbin/route add default gw ${GATEWAY}

    OK,啟動時讀取的配置檔是/etc/sysconfig/static-routes ,它的語法和Redhat是一樣的,請參照建立此文件。

    啟動服務程式
    新建啟動腳本S03server:
    #!/bin/sh
    #------------------------------------------------------------------
    #-- Source
    #-- Author(s) : kendo
    #-- Email: kendo999@sohu.com
    #-- http://www.skynet.org.cn
    #-- 2005/10/31
    #------------------------------------------------------------------

    . /etc/sysconfig/bootserver

    if [ "$enable_httpd" = 1 ] ; then
    . /etc/scripts/httpd.sh $1
    fi

    if [ "$enable_adsl" = 1 ] ; then
    ……
    fi

    if [ "$enable_udhcpd" = 1 ] ; then
    ……
    fi

    很簡單,根據相應變數的值,調用相應的腳本。
    1、這些啟動標誌變數,我定義在了/etc/sysconfig/bootserver當中,其內容如下:
    #start server on system boot
    #1:yes 0:no
    enable_httpd=1
    enable_adsl=1
    enable_udhcpd=1

    2、每種服務對應的腳本,我都放在了/etc/scripts下麵。這些腳本,取決於你打算使用哪些服務程式了。腳本的來源,可以自己編寫,有可能其源碼中自帶有,也可以到網上查找……我就不再一一贅述了,

    OK,基本上,腳本的修改就完成了,下一步,將是建立RamDisk。

    ——————————————————————————————————————————————
    附,讀取網卡配置檔,啟動網卡的C源碼:
    /************************************************************************
    ** author:kendo
    ** date:2005/10/26

    ***********************************************************************/

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <dirent.h>
    #include <unistd.h>

    #define NETCFGDIR "/etc/sysconfig/network-scripts/"

    struct _ifcfg{
    char device[8];
    char bootproto[8];
    char br[16];
    char netmask[16];
    char ip[16];
    char network[16];
    int onboot;
    };

    void ParseKey(struct _ifcfg *ifcfg,char *key,char *value)
    {
    if(!strcmp(key,"DEVICE"))
    {
    strcpy(ifcfg->device,value);
    }
    else if(!strcmp(key,"BOOTPROTO"))
    {
    strcpy(ifcfg->bootproto,value);
    }
    else if(!strcmp(key,"BROADCAST"))
    {
    strcpy(ifcfg->br,value);
    }
    else if(!strcmp(key,"IPADDR"))
    {
    strcpy(ifcfg->ip,value);
    }
    else if(!strcmp(key,"NETMASK"))
    {
    strcpy(ifcfg->netmask,value);
    }
    else if(!strcmp(key,"NETWORK"))
    {
    strcpy(ifcfg->network,value);
    }
    else if(!strcmp(key,"ONBOOT"))
    {
    ifcfg->onboot=(strcmp(value,"yes") ? 0 : 1);
    }
    }

    int main(int argc,char **argv)
    {
    FILE *fp;
    DIR *dir;
    int i;
    char filename[50],buf[80];
    char *index,*key,*value,*p;
    struct _ifcfg *ifcfg;
    struct dirent *ptr;

    ifcfg=(struct _ifcfg *)malloc(sizeof(struct _ifcfg));
    memset(ifcfg,0,sizeof(struct _ifcfg));

    dir=opendir(NETCFGDIR); /*打開腳本目錄*/
    while((ptr=readdir(dir))!=NULL) /*讀取所有檔*/
    {
    if(strncmp(ptr->d_name,"ifcfg-eth",9)) /*這裏,只啟動了乙太網卡^o^*/
    {
    continue;
    }
    memset(filename,0,sizeof(filename));
    sprintf(filename,"%s%s",NETCFGDIR,ptr->d_name);
    if((fp=fopen(filename,"r"))==NULL) /*打開配置檔*/
    {
    continue;
    }

    while(!feof(fp))
    {
    memset(buf,0,sizeof(buf));
    if(fgets(buf,80,fp)!=NULL) /*逐行讀取分析*/
    {
    p=strchr(buf,'n');
    if(p)
    {
    *p='';
    }
    index=buf;
    key=strtok(index,"="); /*讀取配置變數*/
    value=strtok(NULL,"="); /*讀取變數的值*/
    ParseKey(ifcfg,key,value); /*分析之,存入結構ifcfg中*/
    }
    }
    /*構建相應的命令*/
    memset(buf,0,80);
    strcpy(buf,"/sbin/ifconfig");

    if(ifcfg->onboot)
    {
    sprintf(buf,"%s %s %s netmask %s broadcast %s",
    buf,
    ifcfg->device,
    ifcfg->ip,
    ifcfg->netmask,
    ifcfg->br);
    /*直接調用system來實現,當然也可以自己通過ioctl來設置,相應源碼,我以前在c/c++版發過*/
    system(buf);
    }
    }
    free(ife);
    return 0;
    }

    platinum 2005-11-1 02:52

    CODE:

     memset(buf,0,80);
     strcpy(buf,"/sbin/ifconfig");</p> <p>if(ifcfg->onboot)
     {
     sprintf(buf,"%s %s %s netmask %s broadcast %s",
     buf,
     ifcfg->device,
     ifcfg->ip,
     ifcfg->netmask,
     ifcfg->br);
     /*直接調用system來實現,當然也可以自己通過ioctl來設置,相應源碼,我以前在c/c++版發過*/
     system(buf);
     

    兩個問題
    1、從這段代碼看,實際調用了 /sbin/ifconfig 來完成網卡的設置,那麼,這個程式是否必須用 root 來執行?
    2、為何不用 system("command") 呢?

    獨孤九賤 2005-11-1 03:03

    回復 19樓 platinum 的帖子

    1、ifconfig本身運行,應該不需要root吧?而至於在shell中的運行許可權,要看看相應的許可權位了,事實上它已經能夠在我的系統中很好的運行了,測試過很多次的。不過現在我的系統,其實沒有用這種方法的,我是自己封裝了一個網卡管理的庫,也就是重寫了ifconfig,不過要把這些代碼發上來,太麻煩了,所以,就用瞭解system簡單了一點。

    2、我不是很理解“為何不用 system("command") 呢?”這句話的含義,我用的是system(buf);你說的是不是為什麼要去構建一個buf,而不是直接用system("/sbin/ifconfig ethXX……")?清楚一點……^o^


    獨孤九賤 2005-11-16 01:44

    繼續工作,交叉編譯SNMP

    一般系統都會有SNMP的支援,下載了net-snmp-5.1.3.1,先看看INSTALL和FAQ文檔(因為以前從來沒有碰過這個東東,見笑了……),按照說明,在原生主機上安裝了一回,安裝完成後,發現在指定安裝目錄下主要包括了幾塊檔:
    bin:SNMP的一些功能腳本和程式;
    sbin:主要的代理程式和trap程式:snmpd和snmptrap
    include/lib:自身相容及第三方開發所需的頭文件及庫文件;
    share:主要是MIB檔;

    然後回到安裝目錄下,運行./configuare --help,仔細查看了其安裝編譯選項,因為我定位的小型的系統,只需具備基本的SNMP功能即可,所以:
    那些bin目錄下的功能程式也不需要,對應--disable-applications
    bin下的腳本也是不需要的,對應:--disable-scripts
    用戶手冊也不需要:--disable-manuals
    關閉ipv6支持:--disable-ipv6
    還有一個--enable-mini-agent選項,說明是編譯出一個最小化的snmpd,比較有趣,試試先。
    對於交叉編譯,還需要用--host指明目標平臺。

    OK,看完了幫助說明,開始編譯了:
    1、配置,根據以上確定的選項:
    [root@skynet root]# CC=i386-linux-gcc ./configure --host=$TARGET --enable-mini-agent --disable-ipv6 --with-endianness=little --disable-applications --disable-manuals --disable-scripts --disable-ucd-snmp-compatibility

    CC指明了編譯器;--host指明了我的目標平臺,這個環境變數在我前面定義的devedaq腳本中。
    還算順利,繼續編譯它:
    [root@skynet net-snmp-5.1.3.1]# make LDFLAGS="-static"

    呵呵,因為沒有裝lib庫,所以我用了-static選項,指明是靜態編譯;

    3、安裝
    安裝就需要指明安裝路徑了,路徑可以在.config的時候指定,因為那個時候,那串東東太長了,我在install時指定也不遲:
    #make prefix=${TARGET_PREFIX} exec_prefix=${TARGET_PREFIX} install

    4、檢查一下:
    [root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/sbin
    total 2120
    -rwxr-xr-x 1 root root 2164301 Nov 16 09:22 snmpd

    snmpd就是我們要的代理主程序了,大約靜態編譯有2M。

    [root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/bin
    total 4380
    -rwxr-xr-x 2 root root 391980 Oct 14 2004 ar
    -rwxr-xr-x 2 root root 581228 Oct 14 2004 as
    ……

    呵呵,那堆程式和腳本沒有安裝,如snmpwalk……

    ls ${TARGET_PREFIX}/lib
    ls -l ${TARGET_PREFIX}/include


    看看我們需要的mib檔:
    [root@skynet net-snmp-5.1.3.1]# ls ${TARGET_PREFIX}/share/snmp
    mib2c.access_functions.conf mib2c.column_defines.conf mib2c.int_watch.conf mib2c.old-api.conf
    mib2c.array-user.conf mib2c.column_enums.conf mib2c.iterate_access.conf mib2c.scalar.conf
    mib2c.check_values.conf mib2c.conf mib2c.iterate.conf mibs
    mib2c.check_values_local.conf mib2c.create-dataset.conf mib2c.notify.conf snmpconf-data

    5、移植
    基本完成了,因為snmpd太大了點,對它進行strip處理:
    先備個份:
    [root@skynet net-snmp-5.1.3.1]# cp ${TARGET_PREFIX}/sbin/snmpd ${TARGET_PREFIX}/sbin/snmpd.bak
    [root@skynet net-snmp-5.1.3.1]# i386-linux-strip ${TARGET_PREFIX}/sbin/snmpd
    [root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/sbin/snmpd
    -rwxr-xr-x 1 root root 503300 Nov 16 09:30 /home/skynet/tools/i386-linux/sbin/snmpd

    經過處理後,還有近500KB了。

    因為只有SNMP agent功能,即snmpd程式,其他的都可以忽略。用了靜態編譯,lib下邊那些libnetsnmp檔都可以不需要了,程式運行
    需要MIB庫,也就是share下的內容,把這兩個東東拷到rootfs相應的目錄中去:
    [root@skynet net-snmp-5.1.3.1]# cp ${TARGET_PREFIX}/sbin/snmpd ${PRJROOT}/rootfs/usr/sbin
    [root@skynet net-snmp-5.1.3.1]# mkdir -p ${PRJROOT}/rootfs/usr/local/share
    [root@skynet net-snmp-5.1.3.1]# cp -r ${TARGET_PREFIX}/share/snmp ${PRJROOT}/rootfs/usr/local/share
    [root@skynet net-snmp-5.1.3.1]# cp EXAMPLE.conf ${PRJROOT}/rootfs/usr/local/share/snmp/snmpd.conf

    最後一步是把安裝目錄下的配置檔範例拷到snmpd啟動時默認的搜索目錄中去。

    6、測試
    打開snmpd.conf看看:
    [root@skynet net-snmp-5.1.3.1]# vi ${PRJROOT}/rootfs/usr/local/share/snmp/snmpd.conf
    有如下語句:
    # sec.name source community
    com2sec local localhost COMMUNITY
    com2sec mynetwork NETWORK/24 COMMUNITY
    定義了兩個用戶,本地及網路的,以及它們的通讀密鑰,按自己的需要修改一下,如:
    # sec.name source community
    com2sec local 127.0.0.1 public
    com2sec mynetwork 0.0.0.0 public

    後面是定義用戶的用戶組等一大堆東東,事實上不用修改它們了。運行它:
    [root@skynet net-snmp-5.1.3.1]# chroot ${PRJROOT}/rootfs /bin/sh


    BusyBox v1.00 (2004.10.13-06:32+0000) Built-in shell (ash)
    Enter 'help' for a list of built-in commands.

    / # snmpd
    / # exit
    在我們自己的根檔系統環境下運行它,然後退出來。用ps查看:
    #ps -aux
    ……
    root 32270 0.0 0.3 1212 936 ? S 09:38 0:00 snmpd

    [root@skynet net-snmp-5.1.3.1]# netstat -anu
    ……
    udp 0 0 0.0.0.0:161 0.0.0.0:*

    呵呵,已經成功啟動了。用一個SNMP管理軟體試試,可以成功地獲取到資訊。OK!

    總結一下:
    1、主程序+MIB庫大了點,共計約2M,不過我確實沒有辦法再小了,而且一味求小,也不是我的目的。
    2、功能稍微簡單了些,只有agent,如果需要,可以類似地把其他程式加上去就可以了。
    3、第一次玩net-snmp,還是有點生疏,比如我靜態編譯二進位程式,並不需要include/lib下的檔,但是如何關閉它們呢?我試過--disable-ucd-snmp-compatibility,不過好像不是這個選項……下次改進了……

    獨孤九賤 2005-11-16 05:38

    繼續工作,使用ramdisk

    前提:內核編譯時得選相應的支援選項,前文已有敍述。

    1、rootfs中的/boot檔夾刪除;
    2、建立ramdisk:
    使用dd命令建立一個空的檔系統映射:
    # dd if=/dev/zero of=images/initrd.img bs=1k count=8192

    大小8192K,用/dev/zero對其初始化;

    利用剛才的空的檔系統映射,建立檔系統並安裝它,使用了mke2fs命令:
    # /sbin/mke2fs -F -v -m0 images/initrd.img

    新建一個暫存檔案夾做mount之用:
    # mkdir tmp/initrd
    把建好的檔系統mount上來:
    #mount -o loop images/initrd.img tmp/initrd
    把根檔系統拷貝過來:
    #cp -av rootfs/* tmp/initrd
    # umount tmp/initrd

    壓縮:
    # gzip -9 <images/initrd.img > images/initrd.bin

    這樣,就得到了images/initrd.bin

    把目標盤mount上來:
    #mount -t ext2 /dev/hda1 /mnt/cf
    新建一個/boot
    #mkdir /mnt/cf/boot

    把剛才建立的ramdisk鏡像拷過來。然後把內核文件bzImage-2.4.27-rmk5也拷進去。
    這樣,boot檔夾裏邊有兩個檔
    initrd.bin
    bzImage-2.4.27-rmk5

    這個時候還不能安裝lilo,因為lilo的配置檔中有/dev/hda……這樣的東東,而目標盤上還沒有……所以,臨時建一個:
    #mkdir /mnt/cf/dev
    #cp -rf ${PRJROOT}/rootfs/dev/hda* /mnt/cf/dev

    修改${PRJROOT}/rootfs/etc/target.lilo.conf,我的配置檔如下:
    boot=/dev/hda
    disk=/dev/hda
    bios=0x80

    image=/boot/bzImage-2.4.27-rmk5
    initrd=/boot/initrd.bin
    root=/dev/hda1
    append="root=/dev/hda1"
    # label=MyLinux
    read-only

    相比以前的,只是加了一句:initrd=/boot/initrd.bin,另外把label去掉了,因為否則lilo會報怨說語法錯誤。

    好了,可以安裝lilo了。以前我們的語句是:
    lilo -r /mnt/cf -C etc/target.lilo.conf
    現在我們的目標盤上沒有etc這個目錄了,更不用說target.lilo.conf,可以借助於工程目錄中的了原文件,當然,我在目標硬碟上新建了/dev,然後把target.lilo.conf拷過去,還是用這句命令安裝lilo。

    這樣,整個系統就完成了。

    總結:還是想把kernel與檔系統都做到initrd.bin中,不過現在還沒有找到可行的辦法,大家也可以跟貼討論如何來做,偶也好學學……

    3 ***********************************************************



    DIY:自己動手做一個迷你 Linux 系統
    http://www-900.ibm.com/developerWorks/cn/linux/embed/diy/index.shtml#author1#author1

    DIY:自己動手做一個迷你 Linux 系統
    趙蔚 (zhaoway@public1.ptt.js.cn)
    自由職業者
    2002 年 9 月
    本文將帶領大家構建一個迷你型的 Linux 系統。它佔用的硬碟空間遠小於 16M 位元組,但是卻包括了 XFree86 的 X Window 視窗系統。
    目標
    本文要構建的這個迷你型的 Linux 系統只能在一台特定的單機上運行,如果讀者朋友們有興趣的話,在這個系統的基礎上加以改進,是可以構建出通用的、可以在大多數常規 PC 機上即插即用的系統來的。但是這已經不在本文的話題之內了,讀者朋友們如果有興趣,可以通過我的電子郵件和我討論其中的細節問題。
    我們的目標 Linux 系統運行在一台普通的 Intel 386 PC 機上,可以有硬碟,也可以不要硬碟,而用 Flash Disk 來代替。如果是用 Flash 盤的話,需要能夠支援從 Flash 盤?動,而且 Flash 盤的大小要在 16M 位元組或者以上。我們希望用戶一開機?動,就直接進入 X Window 圖形介面,運行事先指定好的程式。不需要用戶輸入用戶名和密碼進行登錄。
    我們設定的這個目標有點像一個 X Terminal 終端工作站。稍加改進,還可以做成乾脆無盤的形式,也就是說,連 16M 的 Flash 盤也不要了。不過,這也超出了本文的話題了。讀者朋友們如果有興趣,可以來信和我進行討論。
    系統?動
    因?我們要考慮從 Flash 盤進行?動,所以我們選擇用 LILO 作?我們的 Boot Loader,而不選用 GRUB。這是考慮到 GRUB 有較強的對硬碟和文件系統的識別能力,而 Flash 盤到底不是標準的硬碟,並且我們選用的文件系統 GRUB 又不一定認識,搞不好的話 GRUB 反會弄巧成拙。而 LILO 就簡單的多了,它在硬碟開始的 MBR 寫入一個小程式,這個小程式不經過文件系統,直接從硬碟磁區號,讀出 Kernel Image 裝入記憶體。這樣,保險係數就大大增加。並且也給了我們自由選用文件系統的餘地。那?,我們要如何安裝 LILO 呢?
    首先,我們要找一塊普通的 800M 左右的 IDE 硬碟,連在目的機器的 IDE 線上。這樣在我們的目的機器上,IDE1 上挂的是 Flash 盤,IDE2 上挂的是一塊工作硬碟。我們用標準的步驟在 IDE2 的標準硬碟上裝上一個 Debian GNU/Linux 系統。當然,如果讀者朋友們手頭沒有 Debian,也可以裝 Red Hat 系統。裝好工作系統之後,要首先做一些裁減工作,把不必要的 Service 和 X Window 等等東西都刪掉。這樣做的目的是增進系統?動速度,因?我們在後面的工作中,肯定要不停的重新?動機器,所以?動速度對我們的工作效率是很關鍵的。
    裝好工作系統之後,在 Falsh 盤上做一個 Ext2 文件系統,這個用 mke2fs 這個命令就可以完成。由於 Flash 盤是接在 IDE1 上的,所以在 Linux 裏面,它的身份是 /dev/hda。本文作者在操作的時候,把整個 Flash 盤劃分了一個整個的分區,所以,調用 mke2fs 的時候,處理的是 /dev/hda1。讀者朋友們應該可以直接在 /dev/hda 上做一個 Ext2 文件系統,而不用事先分區。
    在 Flash 盤上做好了文件系統之後,就可以把一個編譯好的內核映射文件 vmlinuz 拷貝到 Flash 盤上了。注意,必須要先把這個 vmlinuz 映射文件拷貝到 Flash 盤上,然後才能在 Flash 盤上安裝 LILO。不然的話,LILO 到時候可是會 LILILILI 打結巴的,因?它會找不到 Kernel Image 在 Flash 盤上的位置的,那樣的話 Flash 盤也就?動不起來了。還有,如果讀者朋友們在 Flash 盤上用的是一個壓縮的文件系統的話,到時候 LILO 也會出問題,它雖然能正確的找到 Kernel Image 在硬碟上的起始位置,但是它卻沒有辦法處理被文件系統重新壓縮過的這個 Kernel Image,不知道該如何把它展開到記憶體中去。
    把 Kernel Image 拷貝過去以後,我們就可以動手編輯一份 lilo.conf 文件,這份文件可以就放在工作系統上就行了。但是注意在 lilo.conf 中索引的檔案名的路徑可要寫對。這些路徑名都是在工作系統上看上去的路徑名。比如,如果 Flash 盤 Mount 在 /mnt 目錄下面,那?,在 lilo.conf 中,vmlinuz 的路徑名就是 /mnt/vmlinuz。注意這一點千萬不要搞錯。不然的話,如果一不小心把工作系統的 LILO 給破壞掉了,那就麻煩了。編輯好了 lilo.conf,然後再運行 lilo 命令,注意,要告訴它用這個新的 lilo.conf 文件,而不要用 /etc/lilo.conf。
    安裝好 LILO 之後,我們可以立即重新?動,測試一下。首先在 BIOS 裏面,設置成從 IDE1 開始?動,如果我們看到 LILO 的提示符,按回車後還能看到 Kernel 輸出的消息,這就算是 LILO 的安裝成功了。記得這個操作的方法,以後每次我們更新 Flash 盤上的 Kernel Image,都記得要更新 LILO。也就是說,要重新運行一遍 lilo 命令。
    編譯內核
    試驗成功 LILO 的安裝以後,我們開始考慮編譯一個新的內核。當然,要編譯新的內核,我們首先要進入我們的工作系統。這裏有兩個辦法進入工作系統,一是在 BIOS 裏面設置從 IDE2 ?動,當然,這就要求當初安裝工作系統的時候,要把 LILO 安裝在 /dev/hdb 上;另一個辦法是還是從 IDE1 ?動,不改變 BIOS 的設置,但是在看到 LILO 的提示符的時候,要鍵入 linux root=/dev/hdb1,最前面的 linux 是在 lilo.conf 裏面定義的一個 entry,我們只採用這個 entry 所指定的 Kernel Image,但是用 /dev/hdb1 作? root 文件系統。兩個辦法可能有的時候一個比另一個好,更方便一些。這就要看具體的情況了。不過,它們的設置並不是互相衝突的。
    在編譯內核的時候,由於我們的內核是只有一台機器使用的,所以我們應該對它的情況了如指掌;另外一方面,?了減低不必要的複雜性,我們決定不用 kernel module 的支援,而把所有需要的東西直接編譯到內核的裏面。這樣編譯出來的內核,在一台普通的 586 主板上,把所有必要的功能都加進去,一般也不到 800K 位元組。所以,這個辦法是可行的。而且減低了 init forbiddens 的複雜程度。從運行方面來考慮,由於需要的 kernel 代碼反正是要裝載到記憶體中的,所以並不會引起記憶體的浪費。
    在我們的目標平臺上,我們希望使用 USB 存儲設備。還有一點要注意的,就是對 Frame buffer 的支援。這主要是?了支援 XFree86。一般說來,如果我們的顯卡是 XFree86 直接支援的,那當然最好,也就不需要 frame buffer 的內核支援。但是如果 XFree86 不支援我們的顯卡,我們可以考慮用 VESA 模式。但是 XFree86 的 VESA 卡支援運行起來不太漂亮,還有安全方面的問題,有時在?動和退出 X Window 的時候會出現花屏。所以我們可以採用 kernel 的 vesa 模式的 frame buffer,然後用 xfree86 的 linux frame buffer 的驅動程式。這樣一般就看不到花屏的現象了,而且安全方面也沒有任何問題。
    devfs 也是我們感興趣的話題。如果 kernel 不使用 devfs,那?系統上的 root 文件系統就要有 /dev 目錄下面的所有內容。這些內容可以用 /dev/MAKEDEV 腳本來建立,也可以用 mknod 手工一個一個來建。這個方法有其自身的好處。但是它的缺點是麻煩,而且和 kernel 的狀態又並不一致。相反的,如果使用了 devfs,我們就再也不用擔心 /dev 目錄下面的任何事情了。/dev 目錄下面的專案會有 kernel 的代碼自己負責。實際使用起來的效果,對記憶體的消耗並不明顯。所以我們選擇 devfs。
    busybox
    有了 LILO 和 kernel image 之後,接下來,我們要安排 root 文件系統。由於 flash 盤的空間只有 16M 位元組,可以說,這是對我們最大的挑戰。這裏首先要向大家介紹小型嵌入式 Linux 系統安排 root 文件系統時的一個常用的利器:BusyBox。
    Busybox 是 Debian GNU/Linux 的大名鼎鼎的 Bruce Perens 首先開發,使用在 Debian 的安裝程式中。後來又有許多 Debian developers 貢獻力量,這其中尤推 busybox 目前的維護者 Erik Andersen,他患有癌症,可是卻是一名優秀的自由軟體發展者。
    Busybox 編譯出一個單個的獨立執行程式,就叫做 busybox。但是它可以根據配置,執行 ash shell 的功能,以及幾十個各種小應用程式的功能。這其中包括有一個迷你的 vi 編輯器,系統不可或缺的 /sbin/init 程式,以及其他諸如 sed, ifconfig, halt, reboot, mkdir, mount, ln, ls, echo, cat ... 等等這些都是一個正常的系統上必不可少的,但是如果我們把這些程式的原件拿過來的話,它們的體積加在一起,讓人吃不消。可是 busybox 有全部的這?多功能,大小也不過 100K 左右。而且,用戶還可以根據自己的需要,決定到底要在 busybox 中編譯進哪幾個應用程式的功能。這樣的話,busybox 的體積就可以進一步縮小了。
    使用 busybox 也很簡單。只要建一個符號鏈結,比方 ln -s /bin/busybox /bin/ls,那?,執行 /bin/ls 的時候,busybox 就會執行 ls 的功能,也會按照 ls 的方式處理命令行參數。又比如 ln -s /bin/busybox /sbin/init,這樣我們就有了系統運行不可或缺的 /sbin/init 程式了。當然,這裏的前提是,你在 busybox 中編譯進去了這兩個程式的功能。
    這裏面要提出注意的一點是,busybox 的 init 程式所認識的 /etc/inittab 的格式非常簡單,而且和常規的 inittab 文件的格式不一樣。所以讀者朋友們在?這個 busybox 的 init 寫 inittab 的時候,要注意一下不同的語法。至於細節,就不在我們這裏多說了,請大家參考 Busybox 的用戶手冊。
    從?動到進入 shell
    busybox 安裝好以後,我們就可以考慮重新?動,一直到進入 shell 提示符了。這之前,我們要準備一下 /etc 目錄下的幾個重要的文件,而且要把 busybox 用到的 library 也拷貝過來。
    用 ldd 命令,後面跟要分析的二進位程式的路徑名,就可以知道一個二進位程式,或者是一個 library 文件之間的互相依賴關係,比如 busybox 就依賴於 libc.so 和 ld-linux.so ,我們有了這些知識,就可把動手把所有需要的 library 拷貝到 flash 盤上。由於我們的 flash 盤說大不大,說小倒也不小,有 16M 位元組之多。我們直接就用 Glibc 的文件也沒有太多問題。如果讀者朋友們有特殊的需要,覺得 Glibc 太龐大了的話,可以考慮用 uClibc,這是一個非常小巧的 libc 庫,功能當然沒有 Glibc 全,但是足夠一個嵌入式系統使用了。本文就不再介紹 uClibc 了。
    庫程式拷貝過來以後,我們就可以考慮系統?動的步驟了。?動的時候,先是 lilo,接下來就是 kernel,kernel 初始化之後,就調用 /sbin/init,然後由 init 解釋 /etc/inittab 運行各種各樣的東西。inittab 會指導 init 去調用一個最重要的系統初始化程式 /etc/init.d/rcS,我們將要在 rcS 中完成各個文件系統的 mount,此外,還有在 rcS 中調用 dhcp 程式,把網路架起來。rcS 執行完了以後,init 就會在一個 console 上,按照 inittab 的指示開一個 shell,或者是開 getty + login,這樣用戶就會看到提示輸入用戶名的提示符。我們這裏?了簡單起見,先直接進入 shell,然後等到調試成功以後,再改成直接進入 X Window。
    關於 inittab 的語法,我們上面已經提到過了,希望讀者朋友們去查權威的 busybox 的用戶手冊。這裏,我們先要講一下文件系統的構成情況。
    安排文件系統
    大家已經看到,我們的 root 文件系統?了避免麻煩,用的是標準的 ext2 文件系統。由於我們的硬碟空間很小,只有不到 16M,而且我們還要在上面放上 X Window,所以,如果我們全部用 ext2 的話,Flash 盤的有限空間會很快耗盡。我們唯一的選擇是採用一個適當的壓縮文件系統。考慮到 /usr 目錄下面的內容在系統運行的時候,是不需要被改寫的。我們決定選擇唯讀的壓縮文件系統 cramfs 來容納 /usr 目錄下面的全部內容。
    cramfs 是 Linus Torvalds 本人開發的一個適用於嵌入式系統的小文件系統。由於它是唯讀的,所以,雖然它採取了 zlib 做壓縮,但是它還是可以做到高效的隨機讀取。既然 cramfs 不會影響系統讀取文件的速度,又是一個高度壓縮的文件系統,對於我們,它就是一個相當不錯的選擇了。
    我們首先把 /usr 目錄下的全部內容製成一個 cramfs 的 image 文件。這可以用 mkcramfs 命令完成。得到了這個 usr.img 文件之後,我們還要考慮怎樣才能在系統運行的時候,把這個 image 文件 mount 上來,成?一個可用的文件系統。由於這個 image 文件不是一個通常意義上的 block 設備,我們必須採用 loopback 設備來完成這一任務。具體說來,就是在前面提到的 /etc/init.d/rcS 腳本的前面部分,加上一行 mount 命令:
    mount -o loop -t cramfs /usr.img /usr
    這樣,就可以經由 loopback 設備,把 usr.img 這個 cramfs 的 image 文件 mount 到 /usr 目錄上去了。哦,對了,由於要用到 loopback 設備,讀者朋友們在編譯內核的時候,別忘了加入內核對這個設備的支援。對於系統今後的運行來說,這個 mount 的效果是透明的。cramfs 的壓縮效率一般都能達到將近 50%,而我們的系統上絕大部分的內容是位於 /usr 目錄下面,這樣一來,原本可能要用到 18M 的 Flash 盤,現在可能只需要 11M 就可以了。一個 14M 的 /usr 目錄,給壓縮成了僅僅 7M。
    上面考慮了壓縮問題,下面還要考慮到,Flash 盤畢竟不像普通硬碟,多次的擦寫畢竟不太好,所以我們考慮,在需要多次擦寫的地方,使用記憶體來做。這個任務,我們考慮用 tmpfs 來完成。至於 tmpfs 和經典的 ramdisk 的比較,我們這裏就不多說了。一般說來,tmpfs 更加靈活一些,tmpfs 的大小不像 ramdisk,可以順著用戶的需要增長或者縮小。我們選擇把 /tmp、/var 等幾個目錄做成 tmpfs。這只需要我們在 /etc/fstab 裏面加上兩行類似下面的文字就可以了:
    none /var tmpfs default 0 0
    然後別忘了在 /etc/init.d/rcS 裏面靠近開頭的地方,加上 mount -a。這樣,就可以把 /etc/fstab 裏面指定的所有的文件系統都 mount 上來了。
    X Window
    進行到這裏,讀者朋友們可能會以?,X Window 的安裝可能會很複雜。其實不然,由於我們上面的架子搭好了,X Window 的安裝非常簡單,只需要把幾個關鍵的程式拷貝過來就可以了。一般說來,只需要 /usr/X11R6 目錄下面的 bin 和 lib 兩個目錄。然後,根據用戶各自的需要,還可以做大幅的裁減。比如,如果你的局域網上有一個開放的 xfs 字體伺服器的話,你可以把所有本地的字體都刪掉,而使用遠端的字體伺服器。如果只需要運行有限的程式,別忘了把沒有用的 library 都刪掉。此外,還可以把多餘的 X Window 的 driver 都刪掉,只保留本機的顯示卡所需要的 driver 就可以了。
    當然,這一關免不了要做多次測試。
    其他技巧
    如果你的工作系統式在另外一台機器上,通過局域網和本機互聯的話,ssh 是一個不錯的工具。此外,ssh 中帶的 scp 用起來和普通的 cp 拷貝程式差不多,非常方便。用 ssh 和 scp 來共用文件,遠端試驗,你就可以不需要在辦公室裏跑來跑去的了。
    如果你需要一個 MS Windows 上運行的 X Server 和 xfs 字體伺服器,可以考慮包括在 Red Hat 的 Cygwin 工具箱中的 XFree86 系統。


    台灣災難都是事後算帳
    無人飛行載具(Unmanned Aerial Vehicle,UAV)為什麼沒大量應用於救災行列


    4 *******************************************************************








    Initializing the CF Card

    Let's start with erasing any existing partitions and creating a new one:
    fdisk /dev/sda (or whatever the device is for your CF card)

    In case you are not familiar with fdisk:
    p (prints all existing partitions) d (deletes a partition)
    n (creates a new partition) w writes and exists
    q quits without saving

    Delete all existing partitions and create a default primary Linux partition (type 83) using all available space. Save and exit (w)

    Format the new partition with:
    mkfs.ext2 /dev/sda1 (replace sda1 with your new partition)

    Create a mount point and mount your CF card:
    mkdir /mnt/flash
    mount -t ext2 /dev/sda1 /mnt/flash (sda1 would be the first partition on the device sda. Make sure you replace sda with the equivalent to your CF card)

    And now, let's create a basic directory structure:
    mkdir /mnt/flash/boot
    mkdir /mnt/flash/bin
    mkdir /mnt/flash/dev
    mkdir /mnt/flash/dev/cciss
    mkdir /mnt/flash/etc
    mkdir /mnt/flash/lib
    mkdir /mnt/flash/opt
    mkdir /mnt/flash/proc
    mkdir /mnt/flash/sbin
    mkdir /mnt/flash/tmp
    mkdir /mnt/flash/var
    mkdir /mnt/flash/usr
    mkdir /mnt/flash/usr/bin
    mkdir /mnt/flash/usr/lib
    mkdir /mnt/flash/etc/init.d
    cd /mnt/flash/dev
    /dev/MAKEDEV std
    /dev/MAKEDEV ttyS0
    /dev/MAKEDEV hda
    /dev/MAKEDEV hde
    /dev/MAKEDEV console
    /dev/MAKEDEV audio
    mknod psaux c 10 1
    mknod console c 5 1
    mknod /mnt/flash/dev/hda b 3 0
    mknod /mnt/flash/dev/hdb b 3 64
    mknod /mnt/flash/dev/hdc b 22 0
    mknod /mnt/flash/dev/hdd b 22 64

    Installing Busy Box

    We need a basic set of unix utilities. Given the memory limitation, we will install BusyBox. Busybox provides a set of basic utilities in a single executable.

    Download the latest version (0.60.5 when I wrote this guide)

    Unpack and compile:
    tar -zxf busybox-0.60.5.tar.gz
    cd busybox-0.60.5
    make
    make install

    Install Busybox on your CompactFlash:
    cp -r _install/* /mnt/flash

    Copying GRUB (Boot Loader)

    Let's now copy a few files from the PC to the CF we will need them later on:
    cp /sbin/grub /mnt/flash/sbin
    cp /sbin/fdisk /mnt/flash/sbin
    cp /sbin/mkfs.ext2 /mnt/flash/sbin
    cp /lib/libcrypt.so.1 /lib/libc.so.6 /lib/ld-linux.so.2 /mnt/flash/lib/
    cp /lib/libext2fs.so.2 /mnt/flash/lib/
    cp /lib/libe2p.so.2 /mnt/flash/lib/
    cp /lib/libcom_err.so.2 /mnt/flash/lib/
    cp /lib/libuuid.so.1 /mnt/flash/lib/

    RH9 comes with two boot loaders: LILO and GRUB. I have never been able to get LILO to work on a CF Card. It always stops at the LI prompt (usually writes LILO) and even though I tried all tricks I found on the web for this known problem, none of them worked. That's why we will use GRUB instead.

    Copy all boot files from your PC to the CF Card:
    cp -vax /boot/* /mnt/flash/boot

    Getting a Kernel

    By copying /boot to your CF Card, you have already copied your existing kernel. If that is good enough for you, then you can skip this section.

    I am not going to spend time on the details here, just grab the latest version from www.kernel.org, untar and do:

    make menuconfig (It is important here to select the right processor according to the machine you will be using. See the Processor Type and Features section)

    make menuconfig
    make dep
    make bzImage

    Once it is done, copy the fresh kernel to your CF Card:
    cp arch/i386/boot/bzImage /mnt/flash/boot/vmlinuz
    cp System.map /mnt/flash/boot/

    Making the CompactFlash card bootable

    Now we have to write the MBR on the Compact Flash. Execute GRUB:
    grub

    You will get to the grub> command line. If you do not have curses installed on your PC, you will get: Error opening terminal Linux. If that is the case, try grub --no-curses

    Grub names the drives in a different way. The first drive would be hd0, the second drive would be hd1, and so on. The partition number is specified with a second digit after a comma. For example hd0,0 is the first partition on the first hard drive. Set your root partition with:
    root (hd1,0) you can hit tab twice after hd and you will get a list of option (bash-style) just to make sure you are talking about the right partition. It might not be (hd1,0)

    Install the MBR with:
    install /boot/grub/stage1 (hd1) /boot/grub/stage2 (again, replace hd1 with your CF drive)
    quit

    More details on GRUB, such as creating a boot menu are beyond the scope of this document. Check this article for more information about GRUB on CompactFlash

    Unmount your CF card with umount /mnt/flash. Your CF card is now ready and will get you to your # prompt. However, you will have to specify your kernel, root partition and init scripts at the GRUB> prompt:

    GRUB> root (hd0,0) (or whatever it is)
    GRUB> kernel /boot/vmlinuz root=/dev/hda1 rw init=/bin/sh
    GRUB> boot

    Replace hda1 with the device corresponding to your CF card. In my case is hda1 as I am using an ACS IDE to CompactFlash adapter in my BluePad Tablet PC

    標籤: Linux
  • postfix 對照表

    POSTFIX可以建立一個對照表,用來規範使用者一定要用本機的帳號來寄信,這樣子也可以避免一些惡意的人用這種方法來傳送電子郵件。
    例如我的帳號叫ABC@abc.com.tw,在設定了這個限制之後,如果我要用CDE@abc.com.tw來寄信,就會出現不能寄信的錯誤訊息,訊息裡面會講ABC使用者並不擁有CDE。
    設定方法如下:
    製作對照表
    格式如下
    ABC@abc.com.tw ABC
    也可以用正規式表示法
    別忘了用POSTALIAS專換成資料庫
    然後再POSTFIX的設定檔裡面加入下面的設定
    smtpd_sender_login_maps = pcre:/etc/postfix/[對照表的檔名]
    並加入下面的限制:
    smtpd_sender_restrictions=
    reject_sender_login_mismatch
    這樣子就可以了
    密碼的問題就只有定期更改密碼,如果被猜中了就沒辦法了。
    標籤: Linux