2007年5月30日 星期三

[TCP/IP Illustrated] 簡介

OSI 7 Layers

提到網路,OSI 七層架構是一定要說明一下的;雖然目前大家所使用的 TCP/IP 並沒有完全遵循 OSI 七層架構去實作,不過其定義了一個網路架構的典範,因此還是必須去瞭解架構中每一層間的關係。

以下分別就 OSI 七層中,每一層所負責的工作進行介紹:
  • Physical Layer (實體層)
    負責傳送電子訊號,讓兩台透過網路線連接的電腦可以互相傳遞電子訊號。基本上此層不太需要去深入瞭解,因為這是硬體(NIC)所負責的工作。
  • Data Link Layer (資料鏈結層)
    此層的工作是確保資料傳輸的可靠性,提供更上層資料品質的保證。目前有 HDLC、SDLC....等協定屬於此層。
  • Network Layer (網路層)
    前面提到的兩層是用來負責實體相連機器間的資料傳輸,而 Network Layer 則是負責「網路上」兩部機器之間的傳輸,因此這一層有 routing(擇徑)、addressing(定址)、error handling(錯誤處理)....等功能。
    屬於此層較常用的協定有:
    • IP (Internet Protocol)
      負責在不同網路主機間,傳輸資料的協定。
    • ICMP (Internet Control Message Protocol)
      定義資料在網路上傳輸時若發生問題,錯誤訊息的格式與回報方式。
  • Transport Layer (傳輸層)
    雖然 Network Layer 會負責將資料傳送到遠方的機器,但是卻無法保證資料可以完整無誤的傳送完成(例如:中間的封包沒有傳送至目的地),因此 Transport Layer 就有提供 error recovery 的功能,讓資料傳輸更為可靠。目前有 TCP、X.25....等協定皆屬於此層。
    屬於此層較常用的協定有:
    • TCP (Transport Control Protocol)
      負責讓資料在網路上的不同主機間進行可靠的傳輸,屬於 connection 的通訊協定。
    • UDP (User Datagram Protocol)
      負責讓資料在網路上的不同主機間進行快速的傳輸(但不可靠),屬於 connectionless 的通訊協定。
  • Session Layer (交談層)
    此層負責處理傳送雙方間交談處理與協調,並管理資料的交換,主要的目的在於管控資料何時該傳送、何時該接收、或是傳送接收同時進行。
  • Presentation Layer (展示層)
    先前幾層的目的,是將資料完整無誤的傳至對方主機,但所有資料皆是由 0 與 1 所組成,對方完全不知道資料所代表的意義為何,而 Presentation Layer 的目的就是負責將資料轉換為對方主機瞭解的格式,因此所涉及的工作大概就是字碼轉換、資料轉換、資料壓縮解壓縮....等等。
  • Application Layer (應用層)
    此層所負責的工作是提供作業系統中的應用程式使用網路進行資料的傳輸,包括連線的建立、中止,網路管理的方式....等等。目前有 HTTP、FTP、POP3.....等協定皆屬於此層。
    屬於此層較常用的協定有:
    • Telnet
      遠端登入協定,可用來登入網路上任何一台主機。
    • FTP (File Transfer Protocol)
      用來讓網路上的兩台主機間,進行檔案傳輸的協定。
    • TFTP (Trivial File Transfer Protocol)
      與 FTP 相同功能,但使用的是 UDP 而非 TCP。
    • SMTP (Simple Mail Transfer Protocol)
      將電子郵件傳送至網路上任何一部主機的通訊協定。
    • SNMP (Simple Network Management Protocol)
      可用來透過網路進行主機監控的通訊協定。
    • DNS (Domain Name Server)
      負責將主機名稱轉換為相對應的 IP address。

每一層的關係是密不可分的,每一層都是上一層的基礎,唯有每一層的工作都成功完成,才可以透過 Application Layer 將資料成功的由網路傳遞至對方主機。


TCP/IP 4 Layers


剛學網路,OSI 7 Layers 是肯定不能不知道的,而由於 OSI 七層實在是太多,所以為了實作的方便上,TCP/IP 中改為四層,如下圖所示:(詳細資訊可參考 RFC 1122RFC 1123)

  1. Link Layer
    亦稱為「Data Link Layer」,負責處理與硬體相關的部分,舉凡網路裝置在 OS 中的驅動程式、接在網路裝置上的線材....等等,都屬於此層的範圍。
    代表MAC(因此與 MAC 相關的協定 ARPRARP 也屬於此層)。

  2. Network Layer
    亦稱為「Internet Layer」,負責封包於網路上的移動、routing....等工作。
    代表IP(Internet Protocol)、ICMP(Internet Control Message Protocol)、IGMP(Internet Group Management Protocol)。

  3. Transport Layer
    負責建立主機兩端之間的資料流,藉以傳遞資料。
    代表TCP(Transmission Control Protocol)、UDP(User Datagram Protocol)。
    TCP:為可靠的資料傳輸,因此下一層的 Application 不需考慮資料是否正確完整傳遞。
    UDP:不可靠的資料傳輸,因此若需要考慮資料是否有正確完整傳輸,必須實作於 Application Layer。

  4. Application Layer
    處理應用程式的相關係節,一般常見到的應用程式有 TelnetFTPSMTPSNMP....等等。

基本上每層的運作是各司其職,只要對於自己的上下兩層提供介面,可以接收來自下層的訊息,進行正確處理後,再正確的往上傳遞即可。因此假設使用者使用的是 FTP 或是 SMTP 服務,對於 Link Layer 來說,也只是負責傳送不同的 01 組合的電子訊號而已。

由於 Internet 的發展已經有一段歷史了,從原本的小型網路,逐漸的擴大變成現在的全球網路,而用來連接不同 network 的設備,稱為 router;此外,當然還會有很多廠商做出不同的硬體來連上 Internet,其中比較常見的架構有 Ethernet、Token Ring、PPP、FDDI....等等。而這些硬體若是支援 TCP/IP,基本上是可以沒有問題的相互連結並傳遞資料,而這是如何做到呢? 其實就是使用 router 所連接起來的,以下用一張圖來解釋:

router 擁有多個實體介面,支援多種不同的網路架構,當然也認識不同網路架構所產生的封包格式;而 router 除了認得許多不同的封包格式外,還提供了 routing 的功能,可將資料在不同的 network 之間傳遞,而傳遞的依據正是 IP header 中所包含的資訊。

【備註】router 屬於 Network Layer 的硬體

然而在 TCP/IP 的架構中,資料從 Application Layer 傳遞下來後,在 Network Layer 中會加入 IP header,在裡面放置對方的資訊,router 接收到後,就可以知道此封包應該透過那個介面傳遞出去了!

當然,還會將封包的格式進行「Ehternet -> Token Ring」或是「Token Ring -> Ethernet」的轉換! 到了對方網路中,OS 中的 driver 才可以正確辨識。


另外,還有一個值得一提的硬體設備,稱為「bridge」,負責連接相同網路架構的小型 LAN,進而成為一個單一個 LAN,屬於 Link Layer,因此無法連接不同的網路硬體架構。


TCP/IP Layering

TCP/IP 協定中並非只有 TCP 與 IP 兩個協定,而是由許多不同協定結合而成 TCP/IP protocol suit,只是 TCP 與 IP 是其中兩個較為重要的協定,以下用一張圖來表示各協定的分層:

  • TCP
    屬於 Transport Layer,提供可靠的傳輸,因此即使在 Network Layer 中的 IP 屬於不可靠的傳輸也無所謂,因為上層已經加上確認的功能。而 base 在 TCP 協定上的應用也很多,例如:Telnet、FTP、SMTP....等等。
  • UDP
    用來傳送與接收應用程式所發的 datagram,由於傳送後並沒有機制可以確認對方是否收到,因此屬於不可靠傳輸;雖然如此,還是有許多應用,例如:SNMP、VPN....等等。
  • IP
    為 Network Layer 中最重要的協定,作用是進行網路的繞徑(routing),因此為了讓應用程式的資料可以在網路上正確傳送,TCP 與 UDP 都不可避免的會使用到 IP。
  • ICMP
    可說是 IP 的附屬協定,作用是 packet 透過 IP 進行 routing 時,用來與對方主機或傳送路經上的 router 交換一些重要或是錯誤的訊息。一般來說,ICMP 大多是給 IP 所使用,但也有可能被更上層的應用程式所使用,例如:ping、traceroute....等程式。
  • IGMP(Internet Group management Protocol)
    此協定會送出 UDP datagram 給網路上的多台主機(注意! 並非所有主機! 跟 broadcast 不同),稱為 multicasting。
  • ARP(Address Resolution Protocol) 與 RARP(Reverse Address Resolution Protocol)
    用來處理 NIC MAC address 與實體 IP address 的對應,也是提供給 IP 所使用。


網路位址

每一個主機要連上網際網路,都必須要有一個 public IP address,而 IP address 長度為 32 bit,以每 8 bit 為一區間,再將其轉換為數字,會變成類似以下的內容:

140.137.1.5
140.137.20.100
.......等等

而 InterNIC 為了管理方便,將所有的 IP address(32 bit 一共會有 2^32 個 IP address 可用) 分為五個等級,每個等級的子網路切割的方式都不相同,詳細的說明可以參考此篇文章(StudyArea->學習網路->TCP/IP基礎->IP位址)Net Mask 的部分。

以下僅用一張圖來說明五個等級的網段,IP address 分配的情形:



Encapsulation

當應用程式要透過網路傳送資料時,資料必須經由 Application Layer 往下層傳送,最後到 Link Layer 後再透過網路卡出去,中間針對資料進行了許多的加工(最後加工後的資料大小會介於 46~1500 bytes 之間),才可以讓資料正確無誤的傳送至對方主機上,以下用一張圖來說明:

  1. Application(Application Layer) -> TCP(Transport Layer)
    加入了 Applcation header 到原本的資料前方,此時稱為 Application data
  2. TCP(Transport Layer) -> IP(Network Layer)
    再加入 TCP header(20 bytes) 到資料前方,稱為 TCP segment
  3. IP(Network Layer) -> Ethernet driver(Link Layer)
    再加入 IP header(20 bytes) 到資料前方,此時稱為 IP datagram(packet)
  4. Ethernet driver(Link Layer) -> Ethernet
    最後再加入 Ethernet header 以及 Ethernet tailer 到資料的頭尾,此時稱為 Ethernet frame
以上說明的是 TCP 應用程式傳送資料時的情形,但如果是 UDP 呢? 其實也是一樣的,差別僅在於在 Application(Application Layer) -> TCP(Transport Layer) 這一段中,加入的是長度為 8 byes 的 UDP header,成為 UDP datagram。

接著,有一個很重要的觀念,即是「要如何判斷資料是屬於那個應用程式? 或是那個協定呢?」,這邊從最上層往下開始講起:
  • Application(Application Layer) -> TCP(Transport Layer)
    在 Transport Layer 中,TCP 或是 UDP,為了辨識來自上一層的資料是屬於何種應用程式,在TCP header(或 UDP header) 中,有兩個個長度為 16 bit,名稱為「source port number」以及「destination port number」的欄位,是用來紀錄兩端主機的應用程式所使用的 port number,以下列出幾個應用程式:(若想瞭解更多應用程式所使用的 port number,可參考 RFC 1340)
    應用程式
    Protocol
    port number
    FTP
    TCP
    21
    SSH
    TCP
    22
    SMTP
    TCP
    25
    DNS
    TCP
    53
    UDP
    53
    HTTP
    TCP
    80
  • TCP(Transport Layer) -> IP(Network Layer)
    在 Network Layer 中,最重要的就是 IP 協定了! 有許多協定(TCP、UDP、ICMP、IGMP)都必須將資料交給 IP 來處理,然而 IP 要怎麼判斷這些協定為何,或是屬於一層呢? 其實作法很簡單,只要在 IP header 中加入辨識各協定的資訊即可,因此在 IP header 中有一個長度為 8 bit,名稱為「protocol」的欄位來儲存用來判斷這些協定的資訊,而對照表如下:
    協定
    decimal
    binary
    ICMP
    1
    00000001
    IGMP
    2
    00000010
    TCP
    6
    00000110
    UDP
    17
    00010001
    ====== 以下是備註 ======
    看到這邊,可能有人會認為,為什麼在 Network Layer 中的 protocol 欄位,所加入的協定辨識資訊會有 ICMP 跟 IGMP 呢? 不是應該只有 TCP 與 UDP 嗎? 因為 IP 與 ICMP、IGMP 都屬於同一層阿....
    原因是在上述這四個通訊協定都會傳送資料給 IP(各協定遞送資料的關係可以參考上一個部分的圖來瞭解協定之間資料傳遞的關係),因此在 IP header 中的 protocol 欄位必須要將這些協定作區隔。
  • IP(Network Layer) -> Ethernet driver(Link Layer)
    當然在 Link Layer 中,也要能夠判斷來自上一層的資料是屬於什麼協定(IP or ARP or RARP),因此同樣在 Ethernet header 中也有一個長度 16 bit 的欄位,名稱為「frame type」的欄位,用來儲存辨識來自上層(不一定是上層)協定的資料。
    ====== 以下是備註 ======
    同樣的,IP 與 ARP、RARP 也屬於不同的 Layer,也是因為這三個協定都會直接傳送資料給 Ethernet driver,因此在 Ethernet header 中的 frame type 欄位必須要儲存這些協定的辨識資訊。

看到這邊,大概也有些眉目了,資料的 Encapsulation 是會根據所使用的協定,一層一層的由上而下,將特定的辨識資訊加入至 header 中,只要參考上一個部分的圖,就可以清楚瞭解各協定間資料傳遞的情形,觀念自然會清晰不混淆。


Demultiplexing

上一段介紹從上層到下層的過程中,下層會根據來至上層的資料,在 header 中加入辨識資訊以供辨識,那到了對方主機後,自然資料會從 Link Layer(or Network Layer) 開始拆解 header 一訓,一層一層往上,最後到 Application Layer 由應用程式接收並處理,而這個過程,就稱為「Demultiplexing」。

以下用一張圖來進行說明:

  1. Ethernet header
    當 NIC 接收到來自對方主機的 Ethernet frame 之後,會根據 Ethernet header 中的 frame type 欄位,判斷資料是要傳給那個協定,可能是 IP(Network Layer),或是 ARP、RARP(Link Layer)。
  2. IP header
    當資料拆掉 Ethernet header 後傳送給 IP,此時 IP 就可以根據 IP header 中的 protocol 欄位,判斷資料要傳送的協定是 ICMP、IGMP(Network Layer) 或是 TCP、UDP(Transport Layer)。
  3. TCP(or UDP) header
    而在 TCP(or UDP) header 中,就可以根據 destination port number 欄位,來判斷這個資料是要交給那個應用程式去處理了。



2007年5月26日 星期六

基本 bash 程式設計 (1) - Script & Function

Shell Script 簡介

其實 shell script 說穿了,就是一群指令的集合而已,不過藉由程式設計師的創意,可以寫出功能強大的 shell script 來完成許多複雜的工作,對一個想要讓管理工作更有效率(其實是想偷懶)的管理者來說,實在是不能不學的一門課程。

一些廢話就不說了,應該大家都知道 Linux 的檔案權限吧,shell script 沒有執行(x)權限是沒辦法使用的喔!

再來說明 Shell Script 執行的方式,假設我們有一支 shell script 稱為 alice,裡面有兩行指令,分別是 hatter 以及 gryphon,在 Linux 中,一共有三種方法可以來執行這支 shell script,分別是:
(a) source alice
(b) ./alice
(c) source alice &
這三種方式,都可以順利的執行 alice 這一支 script,但是.......有何差別呢? 答案是....「script 是否進入 subshell 中執行

以下用一張圖來說明三種執行方式的差異:

看出來了嗎? 在 (a) 與 (b) 中,使用者都必須等待程式執行完畢,才能接手繼續工作,而兩者的差異在於 script 是否進入了 subshell 中執行;或許一般人覺得這兩種方式似乎沒有差異,但試想,如果管理者在 subshell 修改了許多 shell 的環境設定,此時 script 進入 subshell 中執行就變的很不一樣了! (例如:有不同的 PATH 設定、其他各種 alias command....等等 )

而第三種呢? 除了 script 進入 subshell 中執行外,而且還是在背景處理,完全不會干擾到管理者目前的工作,此種執行方式在於 script 需要跑相當長一段時間的情況下就相當好用了,管理者可以斟酌使用。


Function (函式) 的使用

現在任何高階的程式語言都講求物件導向了,shell script 當然不能連最基本的 function 功能都不支援囉! 而使用 function 的好處有兩個:
  1. 功能模組化
    這不需要費心解釋吧? 這不就是 function 的主要目的嗎?
  2. 加快速度
    shell script 的 function 就像 Java 中 class 的 static method 一樣,系統會預先配置記憶體位置給他,因此可以直接使用且速度較快! 一般來說,目前電腦的記憶體都相當的大,因此在一般情況下(embedded system 中例外啦....)不需要為了省一點記憶體空間都不用 function,利用 function 可以大大降低工作的複雜度。

而 function 定義的方式有兩種,分別是:
function 函式名稱 {
......

......

}
或是
函式名稱() {
......

......

}
====== 以下為備註 ======
第一種方式在「Ubuntu中直接執行 shell script 會產生錯誤喔! 原因是系統會將「function 函式名稱」視為指令來執行....所以就錯了.....(在 RedHat 系列的 Linux 就很正常!)

不過有個很簡單的方法可以處理,只要在執行之前先 source 該 script 即可

而上述兩種撰寫方式所執行出來的並無不同,管理者儘管選擇自己喜歡的去寫即可。

而在每個使用者登入 Linux 系統時,其實就已經存在很多已經預先定義好的 function,可以打下列指令列出預先定義的 function 及其內容:
shell> declare -f
而 function 跟 script 有何不同呢? 以下分兩點說明:
  1. function 不會執行於 subshell,因此與 script 是在同一個 process 中完成
  2. 當 script 名稱與 function 名稱相同時,執行時會以執行 function 為優先

另外附帶,關於執行順序,優先順序如下:
  1. Alias
  2. 系統中的關鍵字
  3. 函式
  4. 系統中內建的工具
  5. script 或其他執行程式

若有遇到同名的問題,管理者必須瞭解執行的優先順序為何,才有辦法順利的 debug。

基本上,不論是 alias、keyword、function、或是其他程式,都有一個名稱(name),而同樣的名稱,又有可能是 alias、keyword、function.....的名稱,那應該要如何判斷某個名稱(name)的型態為何呢? Linux 中提供了一個好用的工具指令「type」,以下擷取 type 的 manpage 內容:
type [-aftpP] name [name ...]
With no options, indicate how each name would be interpreted if
used as a command name. If the -t option is used, type prints a
string which is one of alias, keyword, function, builtin, or
file if name is an alias, shell reserved word, function,
builtin, or disk file, respectively. If the name is not found,
then nothing is printed, and an exit status of false is
以下舉幾個使用 type 的例子:
# 顯示「file」
shell> type -t bash

# 顯示「keyword」
shell> type -t if
或許平常 type 使用到的機會可能不多,不過或許有天會成為 debug 的利器也說不定喔!


參考資料:
  1. Introduction To Bash Shell Scripting
  2. Learning The Bash Shell, 3/e

[Ubuntu] Aapche 流量管理模組 - cband

我想應該很多人都有透過 Web serevr 來分享檔案的經驗吧!

的確,透過 HTTP 感覺比 FTP 還方便些,尤其是一些不大的檔案時~不過一堆人同時來下載時,上傳頻寬都被吃光了.....@_@

再者,FTP 可以限制流量耶! HTTP 可以嗎? 當然也可以,這篇要介紹的就是在 Apache 中用來支援流量管制的模組「cband」,有了此模組,就可以用 VirtualHost 或是 User 為單位來進行網路流量的管控了

以下的環境是在 Ubuntu 6.10 上實作的喔!

安裝:

安裝部分相當簡單,只要下達以下指令:
shell> sudo apt-get -y install libapache2-mod-cband
這樣就安裝好了,不得不令人再次佩服 Ubuntu 的套件支援實在強大.....


設定:

有別於其他的 distribution 將 Apache 設定都放置於 httpd.conf 中, Ubuntu 中的 Apache 設定都已經「模組化」了!在設定的部分就有幾個地方需要注意的囉! 以下一一說明:

1、模組設定

一般的 distribution 會將所有支援的 module 放在一個目錄中,而在 Ubuntu 中,他會將支援的 module 與啟用的 module 分開放,分別置於以下兩個目錄:
  • /etc/apache2/mods-available (支援的 module)
  • /etc/apache2/mods-enabled (啟用的 module)
看了一下 mods-enabled 中的內容,是以 link 的方式指到 mods-available 目錄中的模組檔案,因此執行以下指令將 cband 模組 link 過去:
# 每個 module 都有兩個檔案需要 link 喔!
shell> sudo ln -s /etc/apache2/mods-available/cband.conf /etc/apache2/mods-enabled/cband.conf
shell> sudo ln -s /etc/apache2/mods-available/cband.load /etc/apache2/mods-enabled/cband.load


2、啟用 cband

接著在 /etc/apache2/apache2.conf (或是在 httpd.conf) 中加入以下兩行設定:
CBandScoreFlushPeriod 1
CBandRandomPulse On
如此一來,Apache server 重新啟動時便可以啟用 cband 的流量限制功能。


3、流量限制設定

最後我們要限制某個 VirtualHost 的流量,可以在 <VirtualHost> 標籤中加入以下設定: (更詳細的介紹與教學可參考官方網站)
# 限制 VirtualHost 整體
# 每秒最大頻寬為 1024 KB

# 每秒最多接收 10 個 request

# 每秒最多 30 個 connection

CBandSpeed 1024 10 30

# 限制每個遠端 IP
# 每秒最大頻寬為 100KB
# 每秒最多 5 個 request

# 每秒最多 10 個 connection
CBandRemoteSpeed 100kb/s 5 10

最後重新啟動 Apache server 即可。


參考資料:
  1. Apache 2 Bandwidth Quota and Throttling
  2. fjufirefox - apache2 流量限制
  3. Apache2限制每个虚拟主机的连接数【mod-cband】
  4. 信望愛技術組部落格 - Mod-Cband(httpd限流工具)安裝方式
  5. AppleBOY’s Blog - 【apache】mod cband 頻寬限制
  6. Bug #96063 in mod-cband (Ubuntu) - Problem with Apache2's Cband Mod

2007年5月20日 星期日

[IPTABLE] 利用 iptables 作封包解析

之前有做過 L7-Filter 來擋 P2P、IM....等軟體,所以我想這應該是可行~

iptables 中可以使用「--string」作封包內容的 parse,不過這需要在 kernel 版本為 2.6.14 之後才有支援囉!

然後,找到以下這篇文章:

IPTables Linux firewall with packet string-matching support

把他留下來....說不定以後會用到。

[BASH] 打造自己的 shell 環境 (3) - Variable

Variable 簡介

這一篇主要介紹的是 variable,中文翻譯為變數! 而在 shell 中要如何定義 variable 呢? 可用以下語法:
# 等號(=)左右無空白
varname(變數名稱)=value(值)
而使用 variable 的方法,則是在 variable 名稱前面加上符號「$」即可。

以下舉個簡單的例子來說明直接下 command 來設定 variable 的使用與停用:(主要指令為「export」與「unset」)
# 設定 variable 的名稱與值
shell> myVar='this is a variable test'

# 將其設定為 environment variable
# 表示在此 login session 中,此 variable 都會有效
shell> export myVar

# 上面兩個指令也可以合併為一個!
shell> export myVar='this is a variable test'

# 輸出 variable 的內容
shell> echo $myVar

# 停用 variable
shell> unset myVar


引號的使用

使用 variable 的時候,有一項必須要注意的地方,即是引號(quote)的使用,單引號與雙引號呈現出來的效果並不相同;在單引號中的內容,即使裡面有 variable,也不會被轉換為對應的值;但若是在雙引號中則相反。

以下舉幾個例子來作個簡單說明:
single_quote_string='Four    spaces    between    these    words.'
double_quote_string="Four spaces between these words."

# 輸出「Four spaces between these words.」
echo $single_quote_string

# 輸出「Four spaces between these words.」
echo "$single_quote_string"

# 輸出「Four spaces between these words.」
echo $double_quote_string

# 輸出「Four spaces between these words.」
echo "$double_quote_string"
從 上面的例子看出端倪了嗎? 當 variable 沒有被雙引號包住時,shell 會將 variable 中的內容是為一個一個 word,並去掉 word 之間多餘的空白,僅留下一個空白;但若有此用雙引號,shell 會將其視為一個單一的 word,因此所有空白將會被保留住。


內建 variable

當然,shell 中一定有些內建的 variable,要辨識他們很容易,因為名稱通通都是大寫;而這些 variable 對於使用者來說都是有意義的,當然也有一些是必須具備高深的 Linux 基礎才可以瞭解的,而這邊不介紹很困難的,而是介紹幾個比較容易懂得內建 variable:
名稱
說明
範例
BASH
目前所使用的 shell 位置
/bin/bash
BASH_VERSION
bash 版本
3.1.17(1)-release
HISTCMD
目前命令所屬的 history 編號
822
HISTFILE
儲存 history 的檔案位置
/root/.bash_history
HISTFILESIZE
儲存 history 的最大數量
1000
PATH
用來尋找 command 的路徑列表
# 每個路徑用符號「:」隔開
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
PS1
命令提示字元
# \u:使用者名稱
# \h:hostname
# \W:current working directory
[\u@\h \W]\$

其中要特別注意的 variable 的是「$PATH」,使用者可以自行加入指令所在的路徑,如此一來,執行該指令時就不需要輸入完整路徑了! 因為 shell 會自己根據 $PATH 中所設定的路徑去逐一搜尋並執行。

假設要加入額外的路徑(例如:/home/user/bin)至 $PATH 中,有以下兩種寫法:
# 較為安全的寫法
PATH=$PATH":/home/user/bin"

# 較不安全的作法
# 被入侵放惡意檔案的話,有可能造成系統損毀
# 因為 shell 會從 $PATH 前面的路經開始搜尋指令
PATH="home/user/bin:"$PATH
瞭解了嗎? 不同的設定方式也會有安全性上的考量喔!

[BASH] 打造自己的 shell 環境 (2) - Shell Option

對 Linux 來說,bash 也是在運作中的 process,而其運作時也是有其相關的設定存在。

在之前有提到使用 file 以及 alias 的方式來打造個人化的 shell 環境,已經可以符合大多數人的需求,不過這邊要介紹的是更進一步,修改 bash 的設定參數,讓 bash 中某些功能運作的方式有所變更;而 bash 中有許多功能選項可以將其設定為開啟(on)或是關閉(off),透過開啟或關閉某些功能,就可以修改 bash 運作的方式囉!

以下介紹幾個 bash 中可設定的功能:(以 Ubuntu 7.04 為例)
名稱
說明
預設
emace
預設進入 emace 編輯模式
on
ignoreeof
不允許使用者直接使用 Ctrl+D 登出,必須下登出的指令
off
noclobber
不允許 I/O redirect 覆寫已經存在的檔案
off
noglob
停用萬用字元(例如:*、?....等等) parse 的功能
off
nounset
當使用一個未定義變數時,顯示錯誤訊息
off
vi
預設進入 vi 編輯模式
off

當然還有其他 option,一共有二十來個,若想知道詳細的資訊,可以查詢 bash 的 manpage


恩....講了半天,好像沒講到要怎麼修改選項..........

在 bash 2.0 版以後,提供了一個好用的 command,叫做「shopt,就是專門用來變更 bash 的功能設定;可以透過此指令開啟或關閉上面介紹的 bash 功能,不過這僅是為了相容性而保留下來的功能而已,因為 shopt 有提供許多額外功能選項來開啟 bash 中的功能,以下簡單介紹幾個功能選項:(以 CentOS 5.0 為例)
名稱
說明
預設
cdable_vars
使用 cd 命令時,可以用變數來指令要變換的目錄名稱
off
checkhash
執行命令時,會檢查系統中的 hash table 判斷是否有被修改過
off
cmdhist
紀錄 command history
on
dotglob
將檔名中的「.」視為路徑
off
execfail
執行到無法執行的檔案,不自動跳出
off
histappend
附加 command history,而非覆寫
off
lithist
若功能啟用,且 cmdhist 功能也啟用,一次執行多個指令時,在 history 中會被紀錄為逐一執行多個命令
off
mailwarn
檢查 mail 是否已經讀取了
off

而開啟或關閉的指令如下:
# 開啟某功能
shell> shopt -s <功能名稱>

# 關閉某功能
shell> shopt -u <功能名稱>


參考資料:
  1. Linux / Unix Command: shopt
  2. Linux / Unix Command: bash

2007年5月19日 星期六

[BASH] 打造自己的 shell 環境 (1) - File & Alias

在 bash 中,要打造屬於自己的 shell 環境,可以從四個地方下手,分別是:
  1. Special file
  2. Alias
  3. Option
  4. Variable

在這邊先來介紹如何使用 special file 與 alsias 來打造個人化的 shell 環境。


Special file

所謂的 special file,也不是什麼很特別的檔案啦! 就只是存在於 home directory 中的一些檔案,大概包含了以下檔案:
  • .bash_profile (或是 .profile)
  • .bash_login (可能不存在)
  • .bash_logout
  • .bash_rc

從檔案名稱可以看出,這些檔案一般都是以隱藏檔的方式存在,原因就是讓一般使用者不去亂修改到檔案中的內容;當然對於使用 Linux 已經一段時間的 user 來說,如果可以透過這些檔案來打造一個方便自己使用的 shell 環境,當當然是很好阿! 所以這邊要來研究一下要怎麼作....

基本上,當 user 登入系統後,系統會為 user 建立 shell 環境,而所參考的檔案,分別是以下順序:
.bash_profile(.profile) -> .bash_login -> .bashrc
以下貼出 Ubuntu 7.04 中的 .profile 內容:(這是要 user 登入時才會執行的喔!)
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d ~/bin ] ; then
PATH=~/bin:"${PATH}"
fi
從檔案中可以看出,.profile 會去執行 .bashrc 中的內容來進行 shell 環境的設定,但是僅有在 user 登入系統時作一次,因此若要加入其他的設定,可以在「. ~/.bashrc」這一行後面任何地方自行加入設定!

而若要進行更細部的調整,產生 subshell 時還要再對 shell 環境進行其他微調,則可以直接編輯 .bashrc。

因此,總結來說,如果要在 login 時進行環境的調整,可以編輯以下兩個檔案:
  1. .bash_profile (或是 .profile)
  2. .bashrc
而在 shell 中還要針對 subshell 進行微調,則就是調整以下檔案:
  • .bashrc

如此,則是利用 file 來打造 shell 環境的方法囉!


Alias

alias 的部分,其實可以說明的並不多,這個方式主要是將常用的語法及參數搭配後,另訂一個好記的名字來使用而已!

以下是一些範例:
alias search=grep

alias ll='ls -al'

alias rm='rm -i'
其實要注意的就是在指令的部分,若是含有參數,讓整個指令有空白的部分,就必須要用單引號將整個指令包住,才會有效。

而這些 alias 的指令,可以自行決定要擺在 .bash_profile 或是 .bashrc 中。

2007年5月17日 星期四

OpenVPN 結合 LDAP 認證機制

上一篇文章中介紹完 OpenVPN 如何與 certificate 搭配來加強傳輸的安全性後,這次要回歸到帳號密碼認證的問題!

原本在 certificate 的模式中,client 只要輸入 client certificate 的密碼即可! (因為帳號內定為 client certificate 中的 common name)

當然 OpenVPN 提供的驗證方法不只這種,除了上述的方式外,還可與 LDAP 或是 RADIUS 此類的遠端服務搭配來進行認證的工作,以下要介紹如何使用 LDAP 來進行認證。

全部的設定皆以上一篇為基礎,保留原有設定,並加入 LDAP 認證用的相關設定,以下是設定內容:

vpn server
# 用來認證使用者帳號密碼的 script
# 【注意】務必用「絕對路徑」指定 script 位置

# 「via-env」的目的是以使用者輸入的訊息作為 script 的參數
auth-user-pass-verify /etc/openvpn/ldap_auth.sh via-env

# 以使用者輸入的帳號為 common name
# 不用 client certificate 中的 common name

username-as-common-name

vpn client
# 以帳號密碼的方式進行認證
auth-user-pass


接著以下是 ldap_auth.sh 的內容:
#!/bin/sh

# LDAP Server 的位址
LDAP_HOST=ldap.example.com

# 檢查輸入是否有錯誤
if [ "$username" = "anonymous" || "$username" = "Anonymous" || -z "$username" || -z "$password" ] ; then
exit 1;
fi

# 查詢 LDAP Server 中的帳號密碼資訊
ldapwhoami -x -h $LDAP_HOST -D uid=$username,ou=users,dc=example,dc=com -w $password

if [ "$?" = "0" ]; then
exit 0;
else
exit 1;
fi
exit 1;
然後要讓此 script 讓 others 可以有執行(x)的權限,如此一來 LDAP 認證應該就可以正常進行了。


假設只要進行 LDAP 的帳號密碼認證就好呢?

或許有人會有這種疑問吧? 或是我多慮了........? @_@...算了,不重要...

如果要取消 client certificate 的密碼認證,只要在 vpn server 中加入以下設定:

# 不需 client certificate 相關資訊
client-cert-not-required
並在 vpn client 中將以下兩行註解:
cert keys/vpn_client_cert.pem
key keys/vpn_client_key.pem
如此一來,只要輸入 LDAP 的帳號密碼就可以完成認證囉!


實作心得感想

為了搞這個整整花了我一天,測試半天,中間一直出錯,但一直找不到錯誤原因........

結果發現加入設定「verb 6」可以變成 debug mode,如此一來顯示出來的訊息就相當詳細了!(當然不值得看的訊息也一堆啦......@_@) debug 也相對方便許多~問題也就解決了.....

2007年5月14日 星期一

Linux server 復活雜記

恩,手賤把整個 server 搞掛了,只是為了搞 LVM,要讓新舊硬碟作替換而已.....結果資料都沒了....嗚嗚..... @_@

花了週末的時間來把服務重建起來,過程中也得到一些東西,以下就作個雜記......

ADSL 斷線重連的 shell script


程式如下:(好吧! 我承認我 shell script 實在不太會寫....)
ppp_exist=`ifconfig | grep ppp`

if [ "$ppp_exist" == "" ]; then
adsl-stop
adsl-start

exit 0
fi
再把它丟到 crontab 每分鐘去執行就好了!

設定 Qos 時的發現

-m --mac-source 只能用在 FORWARD chain 上,無法使用在 POSTROUTING 上........

因此要將 packet mark 標籤起來,只能根據 ip address 來進行了! 無法針對 MAC address,至於為什麼,我也不清楚,等我查到資料再說.....


設定 DNS 的發現

雖然裝了 bind-chroot 套件,不過在目錄 /etc 以及 /var/named 中,與 DNS 相關的設定檔案,都必須要有 symbolic link 指向目錄 /var/named/chroot/etc/var/named/chroot/var/named 中的檔案!

至於檔案 named.caching-nameserver.conf,可以暫時不理他,不過似乎是增加 DNS service 的效能用的.....

另外,整個 named.conf 設定檔,變的跟之前很不一樣,裡面多了 view 的設定,看起來頗有意思,以後有空要來好好研究一下.....


參考連結:
bash 參考連結:
  1. Regular Expressions 正規表示式 例子 RE examples
  2. 鳥哥的私房菜 - 學習 shell scripts
  3. shell script - BASH
  4. 關於>/dev/null 2>&1和&>/dev/null 的疑問
  5. 永遠的 Unix (首頁 > 編程技術 > Shell)

iptables 參考連結:
  1. iptables 入門
  2. iptables Tutorial 1.2.2
  3. iptables 封包過濾規則
  4. netfilter

OpenVPN 與金鑰的搭配使用

重點說明

這次要設定的 OpenVPN,要搭配 X.509 certificate 一同設定;基本上,針對安全性相關檔案的部分,有以下幾項工作必須完成:
  1. 自行建置 CA(certificate authority)外
  2. 必須使用 CA 產生給 vpn server 以及 vpn client 用的 key pair,用於身份辨識之用
  3. 使用 openssl 工具產生 Diffie-Hellman 加密檔,作為資料交換加密之用


環境介紹

這裡所測試的環境,還是與上一篇 static key VPN 所使用的環境一樣,只是這次改用 X.509 certificate 將安全性更為提升,以下用圖示來說明:



設定前的準備

在設定 vpn 前,必須準備以下檔案:

VPN Server
  • CA certificate
  • vpn server certificate
  • vpn server key (務必妥善保護)
  • Diffie-Hellman Key (務必妥善保護)

VPN Client
  • CA certificate
  • vpn client certificate
  • vpn client key (務必妥善保護)

其中 CA 的建置與 key pair 的產生,這邊就不作說明了,詳情可參考之前寫的文章「CA建置(1) - Self-Signed CA 」。

剩下的就只有 Diffie-Hellman Key 的產生了,在一般的教學中會指導使用者怎麼透過 easy-rsa utility 來產生,不過我看了一下原始碼,其實他還是透過 openssl 的指令去產生出來的,況且上面的連結所說明 server 以及 client 的 certificate 與 key 的部分,也不是用 easy-rsa 所產生的,因此這邊不打算用 easy-rsa 來作。

講了一堆廢話,要怎麼作呢? 假設我們要作一個 2048 bit 加密的 key,可用以下指令:
# 參數說明: # dhparam:指定產生 Diffie-Hellman Key
# -out:輸出檔案

# dh2048.pem:輸出檔案名稱
# 2048:表示要加密的長度為 2048 bit

openssl dhparam -out dh2048.pem 2048
整個過程需要蠻長一段時間,如此一來,Diffie-Hellman Key 就順利產生了。

接著透過 scp 將檔案分別傳給 vpn server 以及 client,接下來就準備進行設定工作了。


VPN 設定

vpn server
dev tun

# 使用 TLS mode,並指定用來加密傳輸的 key file
tls-server
tls-auth keys/ta.key 0

# 金鑰相關設定
ca keys/cacert.pem
cert keys/vpn_server_cert.pem
key keys/vpn_server_key.pem

# server 與 client 之間交換金鑰時的加密用檔案
dh keys/dh2048.pem

# 設定啟用時所需密碼的檔案位置 # 有此設定就不需要再輸入密碼了
askpass keys/startup_password

# 設定 client 所分配的 ip 網段
server 10.8.0.0 255.255.255.0

# 紀錄 client 連線資訊的檔案
ifconfig-pool-persist ipp.txt

# 傳給 client 使用的設定檔
# 「redirect-gateway def1」是讓 client 所有的網路流量都透過 vpn server 進出

# 若 vpn server 及 client 在同一個實體網段內,則必須多加上「local」,若沒有,在同網段連上 vpn server 的電腦會無法連外喔!

#push "redirect-gateway local def1"

push "redirect-gateway def1"

# 設定 client 連至內部網路的的 routing 資訊
push "route 192.168.0.0 255.255.255.0"

# server 每 10 發送 ping 指令到 client,確定 client 持續連線
# 若 client 沒有回應,每 120 秒重試一次

keepalive 10 120

# 傳輸資料前進行壓縮
comp-lzo

# 同時最多 10 個 client
max-clients 10

# 以非 root 的身份啟動 vpn service
user nobody
group nogroup

# 以 daemon 的方式啟動 vpn service
daemon

# 不重複讀取 key file # 不重開 TUN 裝置
# 當用非 root 的使用者開啟服務時,必須要有以下兩個設定

persist-key
persist-tun

# Log 資訊
status openvpn-status.log
log openvpn.log
log-append openvpn.log
vpn client
# VPN server 的位址
remote 221.169.40.120

# 以 TLS mode 進行連線
tls-client
tls-auth keys/ta.key 1

# 從 VPN server 取得相關設定
pull

# 指定使用的裝置為 TUN
dev tun

# 金鑰相關設定
ca keys/cacert.pem
cert keys/vpn_client_cert.pem
key keys/vpn_client_key.pem

# 傳輸資料前進行壓縮
comp-lzo

接著,為了讓網路流量可以完全經由 vpn server,因此 server 必須執行以下兩行指令:
echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o ppp0 -j MASQUERADE
其他的問題,就是檢查相關檔案所擺放的路徑是否正確了!


【後記】
後來發現,若 server 與 client 在同一網段內, server.conf 中的 push 設定中,不加上「local」也可以讓網路流量都走 vpn tunnel 順利上網。


參考連結:
  1. OpenVPN 建置方案
  2. 使用 OpenVPN
  3. OpenVPN(Debian)
  4. StudyArea - vpn一問,請高手幫忙一下
  5. OpenVPN 2.0 HOWTO
  6. OpenVPN FAQ
  7. OpenVPN HOWTO
  8. OpenVPN 2.1 Man Page

MySQL 中錯誤訊息「ERROR 1005 (HY000)」的解決方式

今天某個大笨妹傳了 xxx.sql 檔給我,要我 dump 進 MySQL server,結果出現以下訊息:
ERROR 1005 (HY000) at line 53: Can't create table './tgc/Privilege.frm' (errno: 150)
這是啥訊息啊.........google 一下,發現原來是跟 key reference 有關,於是找到以下這篇文章 ,裡面說先把 foreign key check 用以下語法關掉:
mysql> SET FOREIGN_KEY_CHECKS = 0;

# 到時候記得重新開啟
mysql> SET FOREIGN_KEY_CHECKS = 1;
恩.......結果無效.....


由於 table engine 為 InnoDB,於是又找到這篇文章 ,看起來似乎可用,文章中提到用以下語法檢查 InnonDB 的狀態資訊:
mysql> SHOW ENGINE INNODB STATUS;
此時會出現一堆訊息阿.....於是慢慢看慢慢看....結果發現原來是 table name 打錯了,把小寫 L 打成大寫 L........(竟然花了半個小時來處理這種 bug....@_@)

恩....學乖了,以後還是看 log 比較清楚,畫面上給出的訊息真是不清不楚。

2007年5月10日 星期四

[Blogger]AJAX Labels

常用 Blogger 的使用者應該都會覺得,為何 google 在 GMail、Docs.....甚至其他服務,都加入了大量的 AJAX,讓整個使用感更好,但唯獨 Blogger 沒有呢?

不過,還好有國外的 Blogger Hacker 解決了這個問題,將 AJAX 的效果加到了 Blogger 中標籤的部分,稱為「AJAX Labels」。

以下有幾個連結介紹安裝方式:
  1. AJAX Labels Reloads (原作者)
  2. blogger 3.0:超酷的ajax標籤再次升級版(完全替代博客原本的標籤功能)
  3. Blogger Hacked: AJAX Labels Reloaded

2007年5月8日 星期二

建立 static key OpenVPN tunnel

Static Key VPN 這是最容易架設的 vpn server,詳細的設定方式可以參考以下兩個連結:
  1. OpenVPN Static Key Mini-HOWTO
  2. OpenVPN(Debian)

雖然設定過程簡單,不過其中也得到了一些設定心得,搞清楚了一些觀念....

以下是今天實作的環境,用一張簡圖來表示:

最左邊是我手邊用的 NB,其為 vpn client;而 vpn server 則是家中的主機,此台主機做為家中的 NAT 使用。
而設定 vpn tunnel 的目的是在於可以直接在外透過 vpn tunnel 直接連線至家中內部區域網路(192.168.0.0/24)。


設定方式很簡單,以下說明一下設定的內容,首先在 vpn server 的部分
# 使用 TUN 裝置 (routing mode) # 官方建議盡量使用 tun,除非不是使用 IP 協定或是有其他更特殊的用途
dev tun

# 「ifconfig」所設定的 ip,基本上只是 tunnel 兩端用來連結之用,並沒有什麼特殊意義 # 前面的部分指定 tunnel 本地端的 IP 位址 # 後面的部分指定 tunnel 另一端的 IP 位址 # 10.8.0.1 為本地端 vpn server IP # 10.8.0.2 為遠端 vpn client IP
ifconfig 10.8.0.1 10.8.0.2

# 用來加密傳輸資料的 key file
secret static.key

# 針對傳輸的資料進行壓縮 # 必須安裝 lzo 套件才行
comp-lzo

# 以 daemon 模式開啟,並指定 user/group
user nobody
group nobody
daemon

# 若上面設定的 nobody 沒有存取 static key 以及 tunnel 裝置 的權限 # 就必須加上此兩行設定,以避免產生權限不足的問題
persist-key
persist-tun
當然也可以不用設定檔,直接以下指令的方式啟動 vpn server,以下指令可以達到同樣效果:
# 其實也是等於把所有參數在指令中下好是一樣的
shell> openvpn --dev tun --ifconfig 10.8.0.1 10.8.0.2 --secret /etc/openvpn/static.key --comp-lzo yes --user nobody --group nobody --daemon openvpn_daemon --persist-key --persist-key


再來是 vpn client 的設定部分:
# vpn server 的 ip address 或是 domain name
remote home.twcic.net

# 使用 TUN 裝置 (routing mode)
dev tun

# 同樣的,這邊也是指定 tunnel 兩端的 ip # 前面為 local ip,後面為 remote ip
ifconfig 10.8.0.2 10.8.0.1

secret static.key

comp-lzo

# 為了讓 client 可以直接與 server 後面的私有區域網路連線
# 必須設定 routing 資訊

# 注意! 這個部分不是設定在 server 喔!
route 192.168.0.0 255.255.255.0

最後,為了讓 client 可以順利連線到主機後端的私有區域網路,vpn server 必須將 packet forward 的功能開啟,透過以下指令即可:
echo "1" > /proc/sys/net/ipv4/ip_forward
PS. 其實原本就已經開啟了,因為那台本來就是 NAT server .......

如此一來,最基本的 vpn tunnel 就設定完成了!


參考連結:
  1. OpenVPN 建置方案
  2. 使用 OpenVPN
  3. OpenVPN(Debian)
  4. StudyArea - vpn一問,請高手幫忙一下
  5. OpenVPN 2.0 HOWTO
  6. OpenVPN FAQ
  7. OpenVPN HOWTO
  8. OpenVPN 2.1 Man Page

[IPTABLE] Bridging Firewall for ADSL connections

恩,同學研究有需要以下環境:

Internet --- Bridge Firewall Server ---- ADSL client 1 (需要透過撥接取得 Public IP)
--- ADSL client 2 (需要透過撥接取得 Public IP)
--- ADSL client 2 (需要透過撥接取得 Public IP)


中間那台 firewall server 是用來擷取 pcaket 作分析用,只要讓他當一個 Hub or Switch 的角色就好,讓後面的 client 可以直接 ADSL 撥接上網,取得 Public IP。

找了半天,終於找到以下這邊文章....而且還是從 google 庫存頁檔找到的,因為蠻具有參考價值,為了避免不見....就把它留下來了


以下是文章內容:

For a long time I've had the 56k (hah - If I'm lucky) dialup. Between the modem and my local network was a nice Linux firewall, all was good. Then I changed my connection to SDSL from Internode, that was good too. I soon found out that I couldn't put my firewall in as-is, that was bad.

Why Bridging?

The problem is that, like a lot of other DSL networks out there, Internode sees your LAN and their network device at the telephone exchange like its one big Ethernet LAN. Normal firewalls expect two different blocks of IP addresses (or subnets) on their "outside" and "inside" interfaces, eg network number 10 on the inside and 42 on the outside. The problem is with the given setup, network 42 is both on the outside and inside, a real problem for a standard firewall.

A bridging firewall expects all its interfaces on the same network. It looks a lot like an Ethernet switch or a hub and in-fact with no firewall rules it behaves exactly like that. The tricky thing is that it has to act like a switch when passing packets but act like a router when its deciding if it should be passing that packet at all.

It should be mentioned that you only need a bridging firewall when you want the computers on your local network to all have real live addresses (so no NAT) and your ISP is not expecting you to have a router there.

Kernel Patches and changes

The standard Linux kernel has firewalling in it, it also has bridging code, so we're set right? That depends on what version kernel you have. For 2.4.x kernels you need a patch, but the newer 2.6.x kernels have ebtables (which is the project that swallowed up the iptables+bridge code) so no patching is needed.

I a 2.4.x kernel, the bridge code needs a modification so it goes and "asks" the firewall code if it is OK to forward a packet. Without that patch, your bridge code will happily send any packets that come along.

Compiling 2.4.x kernels

Now it used to be quite easy as there was only one source of the firewall-bridge linking code. However the code used to sit with the bridge project at sourceforge but has now moved in with the ebtables project also at sourceforge. The following table may make it easier to understand what patch you need

Kernel versionPatch
2.4.18 bridge-nf-0.0.7-against-2.4.18.diff
2.4.21 ebtables-brnf-3_vs_2.4.21.diff.gz
2.4.22 ebtables-brnf-2_vs_2.4.22.diff.gz

The 2.4.21 kernel patch didn't work cleanly and I needed to manually fix a few files to get it to patch and compile, the good news is the 2.4.22 kernel patch did work cleanly for a stock 2.4.22 kernel.

  • net/Makefile : Add "bridge/netfilter" to the mod-subdirs line
  • net/ipv4/ip_output.c : Add 4 lines from the rej file. Note that in the last file the pointer handle "skb2" is now called "to" and "skb" is called "from" so make sure you make those adjustments when you do your hand-patching.
  • net/bridge/br_netfilter.c : Uses old route table functions and a structure that doesnt have pmtu any more. Use the patch at http://www.linuxhq.com/kernel/v2.5/47/net/bridge/br_netfilter.c.

You probably should also read the documentation with respect to the different patches. Earlier patches have their Bridge document Page while the newer patches are a poorer cousin to ebtables itself on the newer site but you might dredge up something on the ebtables dcoumentation page

For compiling, I enabled bridging, netfilter, iptables and the bridge netfilter support. The kernel compiled fine and I then installed it on the firewall.

Compiling 2.6.x kernels

At the time of this writing, I was unable to use the physdev feature of iptables, which means the bridging firewall was unable to use iptables where the physical interface needed to be specified, iptables gave an invalid argument every time I used -m physdev, I rolled back to kernel 2.4.22.

As previously mentioned, the 2.6.x kernels have ebtables built in, so there is no need for patching. ebtables used to be just for filtering based on layer-2 information, such as ethernet MAC addresses but it now allows the Linux bridge to look at the same things ipfilter can see. Some 2.6 kernel and iptables setups cannot handle the physdev module, so you might need ebtables anyway.

There's two ways of filtering IP packets in 2.6 kernels. You can use ipfilters which can see bridged packets and you can use ebtables which has some limited support of IP. Unless there is a good reason, go with the iptables, it has a lot more features for IP packets.

For compiling, I enabled bridging, netfilter, iptables and iptables physdev. If you want ebtables support too enable , ebtables, ebt: filter table, ebt: log support and ebt: IP filter support. These are found in the networking options submenu of the kernel configuration.

Helper Programs

You will need two helper programs for your firewall. They both don't need patching which is wonderful! The first is iptables for manipulating the firewall rules and the second is bridge-utils which makes the bridges. If you want to use ebtables too, get it as well.

I run the Debian distribution so to download the two required packages was a matter of a apt-get command and I was done. If you don't run Debian I'm sure you'll find the programs for your distribution somewhere.

Configuration

It's remarkably simple to make a bridging firewall. You make the bridge, then you add firewall rules in. I was pleasantly surprised by this; the hardest thing for me was to get a second Ethernet card working in my stupid hardware that has flakey ISA buses and a PCI slot that makes anything in it misbehave, luckily I had 3 other sensible PCI slots.

To make a bridge, I use the following commands:

myfirewall# brctl addbr br0
myfirewall# brctl addif br0 eth0
myfirewall# brctl addif br0 eth1

That was it, one working bridge! This meant that any packets that needed to cross the bridge were allowed through. Next I had to add some firewall rules in. What to put into a firewall is explained much better elsewhere, look at the iptables reference given above.

The way the interfaces are handled changes in the kernels. For 2.4 kernels, you use the standard iptables input and output (-i and -o ) flags to specify what your incoming and outgoing interfaces should be. For 2.6 kernels you need to use the physical device module. So whever you see a rule that has -i or -o flags, replace them with -m physdev --physdev-in or -m physdev --physdev-out to specify which interface you want (this is what breaks on my system). If you use -i and -o it will mis-match because iptables thinks the input and output interfaces are whatever you call the bridge (br0 if you use my example).

Pretty simple stuff. I hope it was helpful for you. If there is a part that doesn't make any sense or you'd like me to explain it better drop me a line at the address below.

Very simple iptables rules example

Here is a very simple example of iptables ruleset. It won't do very much except allow everyone from the inside network to connect and for the reply packets to come back. It's based on Rusty's quick example. It assumes your external interface is eth0. First is the 2.4 kernel example:

iptables -N FORWARD
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state NEW -i ! eth0 -j ACCEPT
iptables -A FORWARD -j DROP

Next is the 2.6 kernel example. The only change is the line specifying what interface we accept new connections from.

iptables -N FORWARD
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state NEW -m physdev --physdev-in ! eth0 -j ACCEPT
iptables -A FORWARD -j DROP

NATing on a Bridging Firewall

It may seem strange that if you have a bridging firewall, why would you use NAT and in fact how can you use it. The answer is you may have several IP address but more computers. Put the servers into the DMZ with real addresses and NAT the PCs.

The setup I have has the hosts with the real and private addresses on the same physical network. This is generally a bad idea and is called multi-netting. If you can, put the private hosts on a third ethernet card.

With multi-netting, you get the bizzare situation where everything revolves around a single interface and the firewall is part bridge, part router, based on what IP address it sees.

The first thing to do is give the bridge interface (br0 in the example) two IP addresses. It needs to be in both the public and private networks to do the routing and NATing. If you are going the three interface method, the third interface gets the private address and the bridge interface gets the public one.

Next, you need to add some firewall rules to do the NAT itself. This is reasonably standard. You will need to qualify the rule with the private LAN address so you don't NAT the public IP addresses too. The example assumes the external IP address is 1.2.3.4

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 --to 1.2.3.4

Finally protect your firewall, it now unfortunately has a public IP address so it can do NAT. You may want to make sure that your daemons, such as SSH, only listen to your private IP addresses. Also some firewall rules such as the following can help. Other than traffic already established, the firewall only accepts traffic to itself if it is from the private LAN IP range and it came from the internal interface and it is destined to the firewall itself. It also accepts traffic on the loopback interface but drops the rest.

iptables -F INPUT
iptables -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED
iptables -A INPUT -j ACCEPT -s 192.168.1.0/24 -i eth1 -d 192.168.1.1
iptables -A INPUT -j ACCEPT -i lo

OpenVPN 簡介

簡介

何謂 VPN(Virtual Private Network) ? 可參考此篇文章 的說明.....

然而,市面上有許多 VPN solution,每個 solution 各有其優缺點,若是要考量到建置成本與彈性,可考慮使用這邊將會介紹的 OpenVPN

那 OpenVPN 有什麼特色呢? 以下是官方網站的簡單說明:
OpenVPN is a full-featured SSL VPN solution which can accomodate a wide range of configurations, including remote access, site-to-site VPNs, WiFi security, and enterprise-scale remote access solutions with load balancing, failover, and fine-grained access-controls.

OpenVPN implements OSI layer 2 or 3 secure network extension using the industry standard SSL/TLS protocol, supports flexible client authentication methods based on certificates, smart cards, and/or 2-factor authentication, and allows user or group-specific access control policies using firewall rules applied to the VPN virtual interface. OpenVPN is not a web application proxy and does not operate through a web browser.
上述說明中,最重要的部分在於 OpenVPN 中的安全機制,是建立在 OSI Layer 2 以及 Layer 3,並非在 Application Layer,不透過 Web Browser 進行操作,由於安全性架構在 OSI 的底層,因此在安全性上自然也是大大的提升。

此外,許多 VPN solution 都是走 IPSec 架構,因此就無法與 OpenVPN 相容了,因為在說明第一行中就提到,OpenVPN 是以 SSL 為安全架構,因此必須考量到實際的情形,已決定是否使用 OpenVPN。


OpenVPN 的優點

然而,OpenVPN 有何優點呢? 以下列舉 OpenVPN 的幾項優點供參考:
  1. 可實作在 OSI Layer 3 甚至於 Layer 2,因此可以傳送 Ethernet、IPX、NETBIOS....等協定的封包,相容性極高
  2. 提供連接 VPN 的使用者統一的通道進行網路傳輸,大大加強了安全性
  3. 透過 VPN 所建立的通道,幾乎可以與目前所有安全機制溝通無礙(例如:https)
  4. 支援代理(proxy)機制
  5. 僅需開啟防火牆的單一 port 即可處理來自多方的連線(multi tunnel),減少被惡意入侵的機會
  6. 管理者可根據需求自行撰寫 script,讓 OpenVPN 可以處理更多複雜的工作
  7. 針對動態 IP 使用者,提供了通透且高效能的服務;即使在使用 VPN 通道的同時更換了 IP,建立好的 VPN 通道也不會就此斷掉
  8. 在 NAT 的環境下運作是毫無問題的
  9. 在任何 OS 平台下皆可安裝
  10. 模組化的設計,因此管理者可以根據需求自行增加或減少 OpenVPN 的功能


資料傳輸方式

OpenVPN 會模擬出虛擬的網路裝置來進行資料的傳輸,而其所使用的虛擬裝置為TUN/TAP driver,而 TUN 以及 TAP 有何不同呢? 以下分別進行說明:

1、tun
可被視為虛擬的點對點裝置,就像一般家用的 modem、ADSL 一樣,使用此虛擬裝置的模式稱為 routed mode,因為是在連線後才決定 vpn 雙方的連線路徑,因此可瞭解 tun 裝置所處理的是 OSI Layer 3 的工作

2、tap
可被視為虛擬的 ethernet 網路卡,可以透過此裝置啟動一個 daemon 來接收 ethernet 訊框,稱為 bridge mode,因為此裝置是以 bridge 的方式來運作,這個是 tun 裝置做不到的! 因為 tap 裝置所處理的是 OSI Layer 2 的工作

最後,由於此兩個裝置處理的是 OSI Layer 2 與 3 的部分,因此自然可以容易的更上層的安全機制進行結合,例如:SSL/TLS(Layer 4)。

雖然這兩個裝置是虛擬的,但卻可以跟一般實體的網路卡一樣的運作,也因為有此特性,以下的情況都可以正常運作:
  • 在搜尋 Windows 內部網路或是區網遊戲時,需要發送廣播封包
  • 非 IP 協定的封包(例如:IPX),也可以透過 vpn tunnel 正常傳輸
  • 可以透過防火牆管理虛擬裝置的流量
  • 可以針對 vpn tunnel 的傳輸進行流量管控


OpenVPN 的缺點

OpenVPN 優點一堆,包括設定方便、功能強大、安全性佳....等等,但也是有缺點的! 最重要的缺點是與目前流行的 IPSec vpn 是不相容的,加上由於許多網路設備內建的都是支援 IPSec 的功能,因此跟OpenVPN 並不相容。

不過這並不要緊,技術是會進步的,相信廠商很快就會把相容於 OpenVPN 的功能也加入其設備中。


安裝 OpenVPN

現在要安裝 OpenVPN 可說是方便多了,Windows 下可以直接到官方網站下載,Linux 下可以直接透過 apt 或是 yum 進行網路安裝。

2007年5月7日 星期一

VPN 基本運作原理

何謂 VPN ?

VPN(Virtual Private Network) 中文翻譯為「虛擬私有網路」,以下從網路上擷取 VPN 的定義進行說明:

原文說明:
A virtual private network (VPN) is a private communications network often used by companies or organizations, to communicate confidentially over a public network. VPN traffic can be carried over a public networking infrastructure (e.g. the Internet) on top of standard protocols, or over a service provider's private network with a defined Service Level Agreement (SLA) between the VPN customer and the VPN service provider. A VPN can send data e.g. voice, data or video, or a combination of these media, across secured and encrypted private channels between two points.
中文說明:
VPN 是利用 Internet IP 的技術,建立 Internet 上的加密通道 (Tunneling) 來架構網際網路上的虛擬內聯網路(VPN),IP網路的擴充性良好,所使用的加密技術是標準的 IPSEC (IP Security) 方式,IPSec 結合了加密(Encryption)、認證(Authentication)、密鑰管理 (Key Management)、數位檢定 (Digital Certification) 等安全標準,具有高度的保護能力。

VPN透過Internet傳送企業重要資料自然成為競爭對手覬覦的對象,因此,保障通訊安全即為建置VPN的首要考量。這裡的安全除了保證資訊的隱密 (Confidentiality),避免第三者「竊聽」到通訊內容,同時還須確保網路傳送內容不被篡改破壞,亦即所謂資料的一致性 (Integrity);另外就是資料來源的驗證(Authentication),確定資料並非來自網際網路上第三者所偽造。至少達成這三點,我們才能確保跨越開放式網際網路的VPN有如專線構成的封閉式內聯網路一樣安全。
而由上述的說明,可瞭解到 VPN 是希望透過價格低廉的 WAN 線路,以 Tunneling 的技術,加上特殊的安全、傳輸等附加機制後,可以破除地理限制,讓 Intranet、Extranet、Internet 都可以用類似區域網路的方式進行連結。


VPN 的優點

VPN 擁有相當多的使用上優點,例如:
  1. 使用 WAN 的線路作為基礎,破除地理因素
  2. 安全性高
  3. 使用與維護成本低
  4. 增加生產力
  5. 原理與使用操作上簡單、容易
  6. 增強企業合作伙伴間、或是與企業與用戶間的聯繫


相關安全機制

由於 VPN 是架構在現有的 WAN 上面,當然在安全性的部分要注意的地方可是相當多,一般來講,大概有以下幾種加強安全性的方式:

1、防火牆 Firewall

防火牆是個很普遍的概念,因此這邊就不多做說明了,除了可參考坊間的許多書籍外,以下再附上介紹防火牆概念的連結資訊:

2、加密 Encryption

加密的方式,大致有以下兩種:
  1. 對稱式加密 Symmetric-key encryption
  2. 非對稱式加密 Public-key encryption

上述兩種加密方式,在密碼學裡面都有詳細的探討,以下附上幾個連結供參考:

3、IPSec

IPSec 的部分其實蠻複雜的,可以閱讀以下兩篇文章,相信觀念會相當清楚:

IPSec 的特色在於其架構於網路層的安全機制,因此即使傳輸層 or 應用層的部分沒有安全機制的防護,IPSec 依然可以保護網路通訊的內容。


Tunneling

VPN 的運作原理即稱為 Tunneling

簡單來說,Tunneling 是一種用於在不同通訊協定間傳遞資料的方法,其運作的在於將資料封包視為另外一個封包中的 Data,並加上不同協定的控制訊息後,轉變為適用於另一種通訊協定的資料封包,進而達到讓資料封包在不同通訊協定間傳遞的目的。

以下用一張圖,來解釋原本的 packet 加上了 encrypt information 以及 tunnel information 後的樣子:


看見了嗎? 要進行 tunneling 的資料,必須額外加掛上一層一層的資訊,雖然安全性與便利性提升了,不過也造成網路傳輸的 overhead 很高,這是管理者必須注意到的地方。

在原本的資料封包中,即使內含的 IP Address 是區域網路的 IP,甚至是自訂的 Protocol,經過加入外層 header information 後,便可以標準的通訊協定進行傳輸,而接收封包的兩端,則必須具有解析封包的能力,因此又稱為 Tunneling Interface。

而 Tunneling 需要三種不同的協定來組合而成:
  1. Carrier Protocol
    用來在網際網路上傳遞封包用的協定
  2. Encapsulation Protocol
    用來包裝原本封包資料用的協定,例如:GRE、IPSec、PPTP、L2TP....etc
  3. Passenger Protocol
    原本封包資料所使用的協定

此外,Tunneling 還可以根據其協定實作的層級不同,分為以下三種:

1、實作於 OSI Layer 2

在 Layer 2 就將 packet 進行封裝有一個相當大的好處,即是此 tunnel 在兩端使用非 IP 的協定時依然可以進行傳輸(IP 屬於 Layer 3),雖然 IP 在 internet 上被廣泛使用,但不代表只有 IP 一種協定,例如 Netware 系統中所使用的 IPX。

在此模式下,若 vpn 兩端要進行傳輸,client 會產生一個虛擬的 Point-to-Point(點對點) 的裝置來與 server 連結,而實作 Layer 2 tunneling 的技術,目前有以下四種較為熱門,不但提供了加密的功能,也提供了使用者認證的機制:
  1. Point to Point Tunneling Protocol (PPTP)
    其為擴充功能後的 PPP 協定,由 Microsoft 所協助發展而成,當然在 Windows 下也直接支援,所建立的 tunnel 可以用來傳送 IP 以及 IPX 的封包,不過主要缺點在於傳輸雙方一次只能建立一個 tunnel
  2. Layer 2 Forwarding (L2F)
    由 Cisco 所發展而成,提供了比 PPTP 更多的功能,在傳輸上較有效率,也可同時產生多個 tunnel
  3. Layer 2 Tunneling Protocol (L2TP)
    廣為使用的協定,原因是因為此協定結合了 PPTP 以及 L2F 的優點,卻沒有其缺點,並可與其他安全機制進行結合
  4. Layer 2 Security Protocol (L2Sec)
    似乎是發展用來處理與 IPSec 相容性的問題

當然選擇使用的 tunneling 協定時,要考量的還有很多,例如:
  1. 支援的使用者認證機制是否廣泛
  2. 是否支援在不同的網路環境下運作,例如:NAT
  3. 是否支援 dial-up 模式以方便僅有動態 IP 的使用者
  4. 是否支援 PKI 安全機制
當然還可能有更多的考量,都是管理者在選擇 tunneling protocol 時,必須針對需求來謹慎考慮的!

2、實作於 OSI Layer 3

實作於 Layer 3 中最著名且最為廣泛使用的 tunneling 技術則是 IPSec 了,IPSec 在前面已經有提供網頁介紹,因此這邊不再贅述;不過 IPSec 所提供的功能相當的多,不過也因此產生了一個很主要的缺點,即是設定過於複雜,不過在許多硬體中都支援 IPSec。

而 IPSec 是如何建立 tunnel 來傳輸資料呢? 有以下兩種方式:
  1. Tunnel mode
    此種模式下,packet 進行傳輸前,會將整個 packet 加密後,再加上 tunnel information 後進行傳輸
  2. Transport mode
    此種模式下,僅針對 packet 中的 data 進行加密(並非整個 packet),再加上 tunnel information 後進行傳輸;這樣做的缺點,在於惡意人士可以知道 packet 實際傳送的 source 以及 destination 為何,不過相對所產生的 overhead 也小。

3、實作於 OSI Layer 4

當然,vpn tunnel 也可以建立於 application layer,而 TLS 以及 SSL 就是為了此目的而產生的。透過此種方式,就可以直接透過 browser 連線到已經實作 SSL 的 https 網站進行相關的認證手續,以便建立起vpn tunnel,此種方式已經被廣泛測試過了,是相當可靠的一種方式。


範例說明

為了瞭解 Carrier ProtocolEncapsulation ProtocolPassenger ProtocolTunnel InterfaceInternet 之間的關係,以下用一個實際的簡單範例進行說明:
  1. 假設使用者透過網路訂購一台電腦,廠商製造完成後,要將此台電腦(原本的資料封包)透過快遞業者送交到使用者手上
  2. 而快遞業者收到廠商委託後,將此台電腦進行裝箱打包(Passenger Protocol)進送貨專用的箱子(Encapsulation Protocol)裡,再來會被統一送至快遞業者的貨物運送中心(Entry Tunnel Interface)
  3. 接著快遞業者用送貨車(Carrier Protocol),行經高速公路、一般道路(Internet)後,送達至使用者家中 (Exit Tunnel Interface)
  4. 最後,使用者打開箱子(Encapsulation Protocol),並取出裡面的電腦(Passenger Protocol)開始使用
由上述的範例可知,其實 Tunneling 的原理僅僅就是如此而已。


參考資料
  1. Virtual private network
  2. How Virtual Private Networks Work
  3. VPN

2007年5月5日 星期六

bash 基本觀念

何謂 shell ?

以 Unix-Like 的作業系統為例,shell 是介於使用者與 OS 之間的的交談介面。所有來自使用者的指令,都會被 shell 轉換為 OS 可以認得的命令並執行,相對的,OS 所回傳的內容自然也會被 shell 轉換為使用者可以辨識的訊息。

以下用一張簡單的圖來說明使用者shellOS 三者的關係:


shell 其中一個很重要的工作,就是將使用者所下達的指令,轉換為可以交由 OS 所執行的命令,以下用一個簡單的 command 為例:
shell> sort -n phonelist > phonelist.sorted
以上指令的作用,在於將 phonelist 檔案中的內容,以數字大小進行排列後,輸出至檔案 phonelist.sorted 中

而 shell 是如何將此段指令進行轉換呢? 它做了以下步驟:
  1. 將整段指令分解為「sort」、「-n」、「phonelist」、「>」、「phonelist.sorted」五個部分,每個部分皆稱為 word
  2. 判斷每個 word 的目的為何:
    「sort」是排序的指令、「-n」以及「phonelist」是參數、「>」以及「phonelist.sorted」被合在一起視為一個 I/O 的指令。
  3. 啟動一個 I/O 的動作,準備將內容寫入 phonelist.sorted 中。
  4. 開始將原檔案進行排序。

每個步驟的執行細節就不在這邊介紹,這裡只是要表達出 shell 在 parse 一個指令大概的流程為何。


bash 的特色與優點

在之後針對 shell 的介紹,都是以 bash 為主,因為它是目前最流行的 shell,功能也相對最為強大;而到底 bash 有哪些特色與優點呢? 以下有兩篇好文章,說明的相當詳細:
  1. Shell by OSL3
  2. 使用 bash 的優點


檔案

在 bash 中,檔案被分為三種,分別是純文字檔、執行檔(binary)、以及目錄(directory),其中目錄結構在學習 Linux 上是個相當重要的議題,不過這邊並不贅述,主要把重心放在 bash 上,而且盡量寫些大家容易忘記的部分。

所以像是符號「~」代表使用者家目錄,這種很基本的觀念,就不再多著墨了!

【備註】在 Unix-Like 的檔案系統,沒有所謂的「副檔名」,並非像 Windows 一樣,*.txt 代表純文字檔、*.exe 代表執行檔....等等,這是必須注意的!

1、檔案名稱與萬用字元

首先,要說明的是隱藏檔,在 Windows 中,隱藏檔是以檔案的屬性來決定;不過在 Linux 中,隱藏檔的檔名則是以「.」作為開頭。

接著介紹萬用字元(wildcard),基本的萬用字元有以下幾種:
萬用字元
符合的內容
?
任何單一字元
*
一個或多個任何字元
[set]
符合[set]中設定的任何字元
[!set]
不符合[set]中設定的任何字元


其中 ? 與 * 的差別就是符合單一字元或是多個字元而已,以下介紹 [set] 的用法:
[set] 描述 符合的內容
[abc] a or b or c
[.,;] 句號 or 逗號 or 分號
[-_] 減號 or 底線
[a-c] a or b or c
[a-z] 任一小寫英文字母
[!0-9] 任一非數字字元
[0-9!] 任一數字 or 驚嘆號
[a-zA-Z] 任一英文字母
[a-zA-Z0-9_-] 任一英文字母 or 數字 or 底線 or 減號


以下用個簡單例子來說明,假設有兩個目錄 /home/user1 以及 /home/user2,想要一次把這兩個目錄列表出來,可以用下指令:
shell> ls /home/user*
假如又要列出上述兩個目錄中,名稱為 a 或是 c 開頭的目錄或檔案,可用以下指令:
shell> ls /home/user*/[ac]*
其他的應用,就是由使用者自行去發揮了!

2、Brace Expansion

在 bash 3.0 以後,提供了 Brace Expansion 的功能,它是以左右大括號來設定字元的篩選條件,的用法跟 wildcard 有點不太一樣,以下直接用範例來說明:
Brace Expansion
符合的內容
b{ed,olt,ar}s
beds, bolts, bars
b{ar{d,n,k},ed}s
bards, barns, baeks, beds
{2..5} 2 or 3 or 4 or 5
{d..h}
d or e or f or g or h


輸入與輸出(I/O)

1、Standard I/O

所謂的 standard Input,可能是來自使用者的鍵盤、或是某個檔案內容; standard output 可能就是使用者的螢幕、印表機、或是其他輸出設備....等等,不過這些都是基本的,一般的 shell 都一定會支援的。

而為了讓 I/O 在使用上更有彈性,bash 支援了 pipeline(管線) 的功能,透過 pipeline 的方式,可以將多個程式結合起來,將 A 程式的 output 當作是 B 程式的 input,如此一來,就可以藉由此方式來完成更複雜的 I/O 工作了! 例:將 mail 檔案中的內容直接透過 lp 指令輸出到印表機上,而不是顯示在螢幕上。

pipeline 的支援,讓許多複雜的 I/O 工作變得容易完成,加上之後會介紹的 filtering 的功能(Linux 中有許多用在 filtering 的指令,例如:catgrepsortcutsedtr....等等),便可以撰寫 shell script 來自動完成許多日常工作。

2、I/O Redirection

redirection 的功能可用來取代原本的 standard input 以及 standard output,分別以符號「<」代表 input,符號「>」代表 output,以下用個範例來說明:
shell> cat < file1 > file2
上述指令會將 file1 的內容複製一份變成 file2,效果等同一下的指令:
shell> cp file1 file2
瞭解了嗎? 在 bash shell 中,I/O 是可以做很多不同變化的。

3、Pipeline

在 standard I/O 中就有提到 pipeline 啦! 它的作用就是將某支程式所產生出來的 output 丟給另一支程式作為 input,所使用的符號為「|」,透過此符號將兩個以上不同的指令連結起來,讓前面指令的 output 成為下一個指令的 input。

以下舉個簡單例子:
shell> ls -al /home | more
此指令會將 /home 目錄中的子目錄以及檔案通通列出來,包含隱藏檔,但是若內容很多,超過畫面一頁可以顯示的範圍,就透過 pipeline,將輸出交給 more 指令來做分頁瀏覽的效果,甚至可以交由 lp 指令直接從印表機輸出。

不過當然實際情況不會這麼簡單,在舉個例子,以儲存使用者帳號資訊的檔案 /etc/passwd 為例,每個使用者的帳號都會一行一行的存於此檔案中,格式如下:
man:x:6:12:man:/var/cache/man:/bin/sh
每行中都包含著非常多的資訊,並且以冒號(:)作為間隔,至於這些資訊代表什麼意思,這邊不多做探討,假設我們只需要使用者帳號的部分,如果管理者希望將使用者帳號以字母的順序作排序後,並交由印表機列印出來,則可透過以下指令來完成:
shell> cut -d: -f1 < /etc/passwd | sort | lp

# 以下指令跟上面的相同
shell> cut -d: -f1 /etc/passwd | sort | lp
看見了嗎? 在指令中把 redirection 跟 pipeline 的功能一起用上了! 如此一來達成我們想要的效果。當然,更複雜的指令也是可以完成,只是這就必須要透過大家的巧思了。


工作管理

由於 Unix-Like 系統強大的工作管理功能,不但讓使用者可以下指令同時做多個工作,也可以讓多個不同使用者同時登入,每個使用者有不同的 login session,可說是真正的 Multi-User 的操作環境。

在下指令進行某工作時,一般正常情況下,必須等到工作處理結束,才可以下另一個指令,但若是工作要處理很久的(例如:大型檔案的搬移),那可就要等半天囉! 但若不想這樣等,可以在指令的最後加上符號「&」,如此一來,工作就會移至背景去執行,馬上就可以下達下一個指令來處理另外一個工作了!

而透過加入符號「&」的指令所處理的工作,會產生一個 process number,供使用者隨時檢視之用,還可以使用 renice 的指令調整工作的處理優先權;此外,若要瞭解目前移至背景處理的工作的狀況,可用指令 jobs 來檢視。

不過需要注意的是,一般的 I/O 工作並不適合移到背景去執行,原因如下:
  1. 因為假如被移到背景的 I/O 工作需要使用者的 input,此時整個工作就會 stop,直到使用者將工作刪除,或是移回前景(foreground)來處理才會繼續。
  2. 假設被移至背景處理的 I/O 工作有任何資料要輸出時,一樣會出現在使用者的螢幕上,這樣一來,就會跟使用者正在處理的工作所產生的訊息混合輸出,造成螢幕訊息很混亂。不過這當然這也不是沒有解決方法,只要利用 redirection 的方式將輸出訊息轉到檔案或是 /dev/null 中,就可以解決此問題了!


特殊字元及引號

Unix-Like 系統提供了強大的功能,當然也需要有許多不同的特殊符號來搭配使用,例如「<」以及「>」使用來處理 I/O redirection,「&」則是將工作移至背景處理....等等,以下介紹各種不同特殊字元及引號的用法:
字元
功能說明
~
home directory
`
command substitution
#
comment
$
variable expression
&
background job
*
string wildcard
(
start subshell
)
end subshell
\
quote next character
|
pipe
[
start character-set wildcard
]
end character-set wildcard
{
start command block
}
end command block
;
shell command separator
'
strong quote
<">
weak quote
<
input redirect
>
output redirect
/
pathname directory separator
?
single-character wildcard
!
pipeline logical NOT


1、引號與跳脫字元的使用

當使用者要在螢幕上單純顯示上述這些符號,為了讓 shell 不會誤判為特殊用途,必須搭配引號以及跳脫字元使用,假設我們要在螢幕上輸出「2 * 3 > 5 is a valid inquality」這一行訊息,其中包含了「*」及「>」兩個特殊字元,以下用幾個例子說明:
# 無法顯示正確訊息,反而會有其他非預期的訊息輸出至名稱為「5」的檔案中
shell> echo 2 * 3 > 5 is a valid inquality

# 正確顯示
shell> echo '2 * 3 > 5 is a valid inquality'

# 正確顯示
shell> '2 * 3 > 5' is a valid inquality

# 正確顯示
shell> echo 2 \* 3 \> 5 is a valid inquality
假設要顯示的訊息中,有引號呢? 如果這次訊息換成「"2 * 3 > 5" is a valid inquality」,這就一定非得要跳脫字元的協助不可了,可用以下指令來完成此需求:
shell> echo \"2 \* 3 \> 5\" is a valid inquality

2、指令過長的處理方式

當使用者下的指令很長時,應該要怎麼處理呢? 這時候可以使用反斜線(\),也就是要使用跳脫字元所用的反斜線,shell 會認為指令尚未結束,讓使用者在下一行繼續輸入。

3、控制鍵

控制鍵可以在許多情況下可能會用到,例如:不小心下錯指令,要趕快停止時,按 Ctrl+C 停止指令的執行;或是想要暫停目前的工作,可按 Ctrl+Z.....等等,善用這些熱鍵,可讓工作更為順利,以下介紹常用的控制鍵:
控制鍵
功能說明
Ctrl + C
終止目前執行中的命令
Ctrl + D
結束輸入
Ctrl + \
終止目前執行中的命令(假設 Ctrl+C 沒有效用的話)
Ctrl + S
停止螢幕輸出訊息
Ctrl + Q
重新輸出訊息至螢幕
Del or Ctrl + ?
清除最後一個字元
Ctrl + U
清除目前命令列中的指令
Ctrl + Z
暫停目前的工作


參考資料:
  1. 認識 Bash Shell
  2. GNU Bash
  3. Shell by OSL3
  4. 使用 bash 的優點
  5. Learning the bash Shell, Third Edition