PIXNET Logo登入

小廷的部落格

跳到主文

歡迎光臨lyt0112在痞客邦的小天地

部落格全站分類:休閒旅遊

  • 相簿
  • 部落格
  • 留言
  • 名片
  • 7月 30 週三 202515:10
  • IPv4 Subnet Mask IP Range

Class B Subnet Blocks
 /20 -- 16*/24 Subnets 
(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(291)

  • 個人分類:電腦資訊
▲top
  • 1月 12 週二 201613:58
  • __DATE__ 和 __TIME__ 編譯時報錯

新版本 gcc 編譯包含 __DATE__ 或者 __TIME__ 程式碼時,可能會報下面的錯誤:
error: macro "__DATE__" might prevent reproducible builds
error: macro "__TIME__" might prevent reproducible builds
(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(1,041)

  • 個人分類:電腦資訊
▲top
  • 11月 29 週日 201511:10
  • Linux 無法開機常見的解法 acpi=off noapic

重點:
系統不能啟動
(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(2,805)

  • 個人分類:電腦資訊
▲top
  • 11月 28 週六 201516:25
  • 用ipset配置linux防火牆


iptables是在linux內核裡配置防火牆規則的用戶空間工具,它實際上是netfilter框架的一部分.可能因為iptables是netfilter框架裡最常見的部分,所以這個框架通常被稱為iptables,iptables是linux從2.4版本引入的防火牆解決方案.
ipset是iptables的擴展,它允許你創建 匹配整個地址sets(地址集合) 的規則。而不像普通的iptables鏈是線性的存儲和過濾,ip集合存儲在帶索引的數據結構中,這種結構即時集合比較大也可以進行高效的查找.
除了一些常用的情況,比如阻止一些危險主機訪問本機,從而減少系統資源佔用或網絡擁塞,IPsets也具備一些新防火牆設計方法,並簡化了配置.
在本文中,在快速的討論ipsets的安裝要求後,我會花一點時間來介紹iptables的核心機制和基本概念.然後我會介紹ipset的使用方法和語法,並且演示ipset如何與iptables結合來完成各種不同的配置。最後,我會提供一些細節和較高級的例子來演示如何解決現實中的問題。
ipset比傳統的iptables擁有顯著的性能提升和擴展特性,比如將單個防火牆規則通過一次配置應用到整個主機所在的組和網絡。
由於ipset只是iptables的擴展,所以也會對iptables進行描述。
在許多的linux發佈中ipset是一個簡單的安裝包,大家可以通過自己的linux發行版提供的包管理工具進行安裝。
需要理解的重點時,同iptables一樣,ipset是由用戶空間的工具和內核空間的模塊兩部分組成,所以你需要將這兩部分都準備好。你也需要"ipset-aware"這個iptables 模塊,這個模塊用來增加 rules that match against sets。(……)
首先我們使用自己的linux發行版的包管理工具對ipset進行搜索。在ubuntu上安裝需要安裝ipset 和 xtables-addons-source 包,然後,運行module-assistant auto-install xtables-addons,等待大約30秒後ipset就可以使用了。
如果你的linux發行版沒有被支持,那就需要根據ipset 首頁中的安裝步驟構建源碼並對內核打補丁。
這篇文章中使用ipset v4.3 和 iptables v1.4.9。
iptables概述
簡單來講,iptables防火牆配置由規則鏈的集合組成,每一個鏈包含一個規則。一個數據包,在各個處理階段,內核商量合適的規則來決定數據報的命運。
規則鏈按照順序進行匹配,基於數據包的流向 (remote-to-local, remote-to-remote or local-to-remote)和當前所處的處理階段(before or after "routing")。參考圖1。
(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(2,874)

  • 個人分類:電腦資訊
▲top
  • 9月 12 週六 201518:22
  • 利用 ipset 封禁大量 IP

使用 iptables 封 IP,是一種比較簡單的應對網絡攻擊的方式,也算是比較常見。有時候可能會封禁成千上萬個 IP,如果添加成千上萬條規則,在一台注重性能的服務器或者本身性能就很差的設備上,這就是個問題了。ipset 就是為了避免這個問題而生的。


關於 iptables,要知道這兩點。



  • iptables 包含幾個表,每個表由鏈組成。默認的是 filter 表,最常用的也是 filter 表,另一個比較常用的是 nat 表。一般封 IP 就是在 filter 表的 INPUT 鏈添加規則。

  • 在進行規則匹配時,是從規則列表中從頭到尾一條一條進行匹配。


這像是在鏈表中搜索指定節點費力。ipset 提供了把這個 O(n) 的操作變成 O(1) 的方法:就是把要處理的 IP 放進一個集合,對這個集合設置一條 iptables 規則。像 iptable 一樣,IP sets 是 Linux 內核中的東西,ipset 這個命令是對它進行操作的一個工具。


簡單的流程


可以用這幾條命令概括使用 ipset 和 iptables 進行 IP 封禁的流程


ipset create vader hash:ip 
iptables -I INPUT -m set --match-set vader src -j DROP
ipset add vader 4.5.6.7
ipset add vader 1.2.3.4
ipset add vader ...
ipset list vader # 查看 vader 集合的內容

下面分別對各條命令進行描述。


創建一個集合


ipset create vader hash:ip 

這條命令創建了名為 vader 的集合,以 hash 方式存儲,存儲內容是 IP 地址。


添加 iptables 規則


iptables -I INPUT -m set --match-set vader src -j DROP 

如果源地址(src)屬於 vader 這個集合,就進行 DROP 操作。這條命令中,vader 是作為黑名單的,如果要把某個集合作為白名單,添加一個 『!』 符號就可以。


iptables -I INPUT -m set ! --match-set yoda src -j DROP 

到現在雖然創建了集合,添加了過濾規則,但是現在集合還是空的,需要往集合裡加內容。


找出「壞」 IP


找出要封禁的 IP,這是封禁過程中重要的步驟,不過不是這裡的重點。簡要說明一下兩種方法思路。


netstat -ntu | tail -n +3 | awk '{print $5}' | sort | uniq -c | sort -nr 

直接通過 netstat 的信息,把與本地相關的各種狀態的 IP 都計數,排序列出來。


或者從 nginx 或者其他 web server 的日誌裡找請求數太多的 IP


awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr 

後半部分,排序,去重,再按次數進行逆向排序的操作,跟上面命令是一樣的。


找出「壞」 IP,往之前創建的集合裡添加就可以了。


ipset add vader 4.5.6.7 

有多少「壞」 IP,就添加多少 IP,因為針對這些封禁的 IP 只需要一條 iptables 規則,而這些 IP 是以 hash 方式存儲,所以封禁大量的 IP 也不會影響性能,這也是 ipset 存在的最大目的。


 


ipset 更多的用法


存儲類型


前面例子中的 vader 這個集合是以 hash 方式存儲 IP 地址,也就是以 IP 地址為 hash 的鍵。除了 IP 地址,還可以是網絡段,端口號(支持指定 TCP/UDP 協議),mac 地址,網絡接口名稱,或者上述各種類型的組合。


比如指定 hash:ip,port就是 IP 地址和端口號共同作為 hash 的鍵。查看 ipset 的幫助文檔可以看到它支持的所有類型。


下面以兩個例子說明。


hash:net


ipset create r2d2 hash:net 
ipset add r2d2 1.2.3.0/24
ipset add r2d2 1.2.3.0/30 nomatch
ipset add r2d2 6.7.8.9
ipset test r2d2 1.2.3.2

hash:net 指定了可以往 r2d2 這個集合裡添加 IP 段或 IP 地址。


第三條命令裡的 nomatch 的作用簡單來說是把 1.2.3.0/30 從 1.2.3.0/24 這一範圍相對更大的段裡「剝離」了出來,也就是說執行完 ipset add r2d2 1.2.3.0/24 只後1.2.3.0/24 這一段 IP 是屬於 r2d2 集合的,執行了 ipset add r2d2 1.2.3.0/30 nomatch 之後,1.2.3.0/24 裡 1.2.3.0/30 這部分,就不屬於 r2d2 集合了。執行 ipset test r2d2 1.2.3.2 就會得到結果 1.2.3.2 is NOT in set r2d2.


hash:ip,port


ipset create c-3po hash:ip,port 
ipset add c-3po 3.4.5.6,80
ipset add c-3po 5.6.7.8,udp:53
ipset add c-3po 1.2.3.4,80-86

第二條命令添加的是 IP 地址為 3.4.5.6,端口號是 80 的項。沒有註明協議,默認就是 TCP,下面一條命令則是指明了是 UDP 的 53 端口。最後一條命令指明了一個 IP 地址和一個端口號範圍,這也是合法的命令。


自動過期,解封


ipset 支持 timeout 參數,這就意味著,如果一個集合是作為黑名單使用,通過 timeout 參數,就可以到期自動從黑名單裡刪除內容。


ipset create obiwan hash:ip timeout 300 
ipset add obiwan 1.2.3.4
ipset add obiwan 6.6.6.6 timeout 60

上面第一條命令創建了名為 obiwan 的集合,後面多加了 timeout 參數,值為 300,往集合裡添加條目的默認 timeout 時間就是 300。第三條命令在向集合添加 IP 時指定了一個不同於默認值的 timeout 值 60,那麼這一條就會在 60 秒後自動刪除。


隔幾秒執行一次 ipset list obiwan 可以看到這個集合裡條目的 timeout 一直在隨著時間變化,標誌著它們在多少秒之後會被刪除。


如果要重新為某個條目指定 timeout 參數,要使用 -exit 這一選項。


ipset -exist add obiwan 1.2.3.4 timeout 100 

這樣 1.2.3.4 這一條數據的 timeout 值就變成了 100,如果這裡設置 300,那麼它的 timeout,也就是存活時間又重新變成 300。


如果在創建集合是沒有指定 timeout,那麼之後添加條目也就不支持 timeout 參數,執行 add 會收到報錯。想要默認條目不會過期(自動刪除),又需要添加某些條目時加上 timeout 參數,可以在創建集合時指定 timeout 為 0。


ipset create luke hash:ip 
ipset add luke 5.5.5.5 timeout 100
# 得到報錯信息 kernel error received: Unknown error -1

更大!


hashsize, maxelem 這兩個參數分別指定了創建集合時初始的 hash 大小,和最大存儲的條目數量。


ipset create yoda hash:ip,port hashsize 4096 maxelem 1000000 
ipset add yoda 3.4.5.6,3306

這樣創建了名為 yoda 的集合,初始 hash 大小是 4096,如果滿了,這個 hash 會自動擴容為之前的兩倍。最大能存儲的數量是 100000 個。


如果沒有指定,hashsize 的默認值是 1024,maxelem 的默認值是 65536。


另外幾條常用命令


ipset del yoda x.x.x.x # 從 yoda 集合中刪除內容 
ipset list yoda # 查看 yoda 集合內容
ipset list # 查看所有集合的內容
ipset flush yoda # 清空 yoda 集合
ipset flush # 清空所有集合
ipset destroy yoda # 銷毀 yoda 集合
ipset destroy # 銷毀所有集合
ipset save yoda # 輸出 yoda 集合內容到標準輸出
ipset save # 輸出所有集合內容到標準輸出
ipset restore # 根據輸入內容恢復集合內容

還有……



  • 如果創建集合是指定的存儲內容包含 ip, 例如 hash:ip 或 hash:ip,port ,在添加條目時,可以填 IP 段,但是仍然是以單獨一個個 IP 的方式來存。

  • 上面所有的例子都是用 hash 的方式進行存儲,實際上 ipset 還可以以 bitmap 或者 link 方式存儲,用這兩種方式創建的集合大小,是固定的。

  • 通過 man upset 和 ipset —help 可以查到更多的內容,包括各種選項,支持的類型等等。


轉載自https://intxt.net/block-ip-with-ipset/



(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(2,669)

  • 個人分類:電腦資訊
▲top
  • 1月 13 週二 201509:37
  • Linux 信號signal處理機制


















Linux 信號signal處理機制



 


 
      信號機制是進程之間相互傳遞消息的一種方法,信號全稱為軟中斷信號,也有人稱作軟中斷。從它的命名可以看出,它的實質和使用很象中斷。所以,信號可以說是進程控制的一部分。

        一、信號的基本概念

            1、基本概念

        軟中斷信號(signal,又簡稱為信號)用來通知進程發生了非同步事件。進程之間可以互相通過系統調用kill發送軟中斷信號。內核也可以因為內部事件而給進程發送信號,通知進程發生了某個事件。注意,信號只是用來通知某進程發生了什麼事件,並不給該進程傳遞任何資料。

        收 到信號的進程對各種信號有不同的處理方法。處理方法可以分為三類:第一種是類似中斷的處理常式,對於需要處理的信號,進程可以指定處理函數,由該函數來處 理。第二種方法是,忽略某個信號,對該信號不做任何處理,就象未發生過一樣。第三種方法是,對該信號的處理保留系統的預設值,這種缺省操作,對大部分的信 號的缺省操作是使得進程終止。進程通過系統調用signal來指定進程對某個信號的處理行為。

        在進程表的表項中有一個軟中斷信號域,該域中每一位元對應一個信號,當有信號發送給進程時,對應位置位元。由此可以看出,進程對不同的信號可以同時保留,但對於同一個信號,進程並不知道在處理之前來過多少個。

        2、信號的類型

        發出信號的原因很多,這裡按發出信號的原因簡單分類,以瞭解各種信號:

        (1) 與進程終止相關的信號。當進程退出,或者子進程終止時,發出這類信號。
        (2) 與進程例外事件相關的信號。如進程越界,或企圖寫一個唯讀的記憶體區域(如程式正文區),或執行一個特權指令及其他各種硬體錯誤。
        (3) 與在系統調用期間遇到不可恢復條件相關的信號。如執行系統調用exec時,原有資源已經釋放,而目前系統資源又已經耗盡。
        (4) 與執行系統調用時遇到非預測錯誤條件相關的信號。如執行一個並不存在的系統調用。
        (5) 在使用者態下的進程發出的信號。如進程調用系統調用kill向其他進程發送信號。
        (6) 與終端交互相關的信號。如使用者關閉一個終端,或按下break鍵等情況。
        (7) 跟蹤進程執行的信號。

      

 








































































































值


名 字


說明


01


SIGHUP


掛起(hangup)


02


SIGINT


中斷,當使用者從鍵盤按ctrl+c鍵


03


SIGQUIT


退出,當使用者從鍵盤按quit鍵時


04


SIGILL


非法指令


05


SIGTRAP


跟蹤陷阱(trace trap),啟動進程,跟蹤代碼的執行


06


SIGIOT


IOT指令


07


SIGEMT


EMT指令


08


SIGFPE


浮點運算溢出


09


SIGKILL


殺死、終止進程


10


SIGBUS


匯流排錯誤


11


SIGSEGV


段違例(segmentation? violation),進程試圖去訪問其虛位址空間以外的位置


12


SIGSYS


系統調用中參數錯,如系統調用號非法


13


SIGPIPE


向某個非讀管道中寫入資料


14


SIGALRM


鬧鐘。當某進程希望在某時間後接收信號時發此信號


15


SIGTERM


軟體終止(software? termination)


16


SIGUSR1


使用者自訂信號1


17


SIGUSR2


使用者自訂信號2


18


SIGCLD


某個子進程死


19


SIGPWR


電源故障



 

        注意 信號SIGKILL和SIGSTOP既不能被捕捉,也不能被忽略。信號SIGIOT與SIGABRT是一個信號。可以看出,同一個信號在不同的系統中值可能不一樣,所以建議最好使用為信號定義的名字,而不要直接使用信號的值。

二、有關信號的系統調用

     系統調用signal是進程用來設定某個信號的處理方法,系統調用kill是用來發送信號給指定進程的。這 兩個調用可以形成信號的基本操作。後兩個調用pause和alarm是通過信號實現的進程暫停和計時器,調用alarm是通過信號通知進程計時器到時。所 以在這裡,我們還要介紹這兩個調用。

        1、signal 系統調用

        系統調用signal用來設定某個信號的處理方法。該調用聲明的格式如下:
        void (*signal(int signum, void (*handler)(int)))(int);
        在使用該調用的進程中加入以下頭檔:
        #include <signal.h>

        上述聲明格式比較複雜,如果不清楚如何使用,也可以通過下面這種類型定義的格式來使用(POSIX的定義):
        typedef void (*sighandler_t)(int);
        sighandler_t signal(int signum, sighandler_t handler);
        但這種格式在不同的系統中有不同的類型定義,所以要使用這種格式,最好還是參考一下連線手冊。

        在調用中,參數signum指出要設置處理方法的信號。第二個參數handler是一個處理函數,或者是
        SIG_IGN:忽略參數signum所指的信號。
        SIG_DFL:恢復參數signum所指信號的處理方法為預設值。

        傳遞給信號處理常式的整數參數是信號值,這樣可以使得一個信號處理常式處理多個信號。系統調用signal返回值是指定信號signum前一次的處理常式或者錯誤時返回錯誤代碼SIG_ERR。下面來看一個簡單的例子:

        #include <signal.h>
        #include <unistd.h>
        #include <stdio.h>
        void sigroutine(int dunno) { /* 信號處理常式,其中dunno將會得到信號的值 */
        switch (dunno) {
        case 1:
        printf("Get a signal -- SIGHUP ");
        break;
        case 2:
        printf("Get a signal -- SIGINT ");
        break;
        case 3:
        printf("Get a signal -- SIGQUIT ");
        break;
        }
        return;
        }

        int main() {
        printf("process id is %d ",getpid());
        signal(SIGHUP, sigroutine); //* 下面設置三個信號的處理方法
        signal(SIGINT, sigroutine);
        signal(SIGQUIT, sigroutine);
        for (;;) ;
        }

        其中信號SIGINT由按下Ctrl-C發出,信號SIGQUIT由按下Ctrl-發出。該程式執行的結果如下:

        localhost:~$ ./sig_test
        process id is 463
        Get a signal -SIGINT //按下Ctrl-C得到的結果
        Get a signal -SIGQUIT //按下Ctrl-得到的結果
        //按下Ctrl-z將進程置於後臺
        [1]+ Stopped ./sig_test
        localhost:~$ bg
        [1]+ ./sig_test &
        localhost:~$ kill -HUP 463 //向進程發送SIGHUP信號
        localhost:~$ Get a signal – SIGHUP
        kill -9 463 //向進程發送SIGKILL信號,終止進程
        localhost:~$

        2、kill 系統調用

        系統調用kill用來向進程發送一個信號。該調用聲明的格式如下:
        int kill(pid_t pid, int sig);
        在使用該調用的進程中加入以下頭檔:
        #include <sys/types.h>
        #include <signal.h>

        該 系統調用可以用來向任何進程或進程組發送任何信號。
如果參數pid是正數,那麼該調用將信號sig發送到進程號為pid的進程。
如果pid等於0,那麼信 號sig將發送給當前進程所屬進程組裡的所有進程。
如果參數pid等於-1,信號sig將發送給除了進程1和自身以外的所有進程。
如果參數pid小於- 1,信號sig將發送給屬於進程組-pid的所有進程。如果參數sig為0,將不發送信號。該調用執行成功時,返回值為0;錯誤時,返回-1,並設置相應 的錯誤代碼errno。下面是一些可能返回的錯誤代碼:
        EINVAL:指定的信號sig無效。
        ESRCH:參數pid指定的進程或進程組不存在。注意,在進程表項中存在的進程,可能是一個還沒有被wait收回,但已經終止執行的僵死進程。
        EPERM: 進程沒有權力將這個信號發送到指定接收信號的進程。因為,一個進程被允許將信號發送到進程pid時,必須擁有root權力,或者是發出調用的進程的UID 或EUID與指定接收的進程的UID或保存使用者ID(savedset-user-ID)相同。如果參數pid小於-1,即該信號發送給一個組,則該錯誤 表示組中有成員進程不能接收該信號。

        3、pause系統調用

        系統調用pause的作用是等待一個信號。該調用的聲明格式如下:
        int pause(void);
        在使用該調用的進程中加入以下頭檔:
        #include <unistd.h>

        該調用使得發出調用的進程進入睡眠,直到接收到一個信號為止。該調用總是返回-1,並設置錯誤代碼為EINTR(接收到一個信號)。下面是一個簡單的範例:

        #include <unistd.h>
        #include <stdio.h>
        #include <signal.h>
        void sigroutine(int unused) {
        printf("Catch a signal SIGINT ");
        }

        int main() {
        signal(SIGINT, sigroutine);
        pause();
        printf("receive a signal ");
        }

        在這個例子中,程式開始執行,就象進入了閉環一樣,這是因為進程正在等待信號,當我們按下Ctrl-C時,信號被捕捉,並且使得pause退出等候狀態。

4、alarm和 setitimer系統調用

        系統調用alarm的功能是設置一個計時器,當計時器計時到達時,將發出一個信號給進程。該調用的聲明格式如下:
        unsigned int alarm(unsigned int seconds);
        在使用該調用的進程中加入以下頭檔:
        #include <unistd.h>

        系 統調用alarm安排內核為調用進程在指定的seconds秒後發出一個SIGALRM的信號。如果指定的參數seconds為0,則不再發送 SIGALRM信號。後一次設定將取消前一次的設定。該調用返回值為上次定時調用到發送之間剩餘的時間,或者因為沒有前一次定時調用而返回0。

        注意,在使用時,alarm只設定為發送一次信號,如果要多次發送,就要多次使用alarm調用。

        對於alarm,這裡不再舉例。現在的系統中很多程式不再使用alarm調用,而是使用setitimer調用來設置計時器,用getitimer來得到計時器的狀態,這兩個調用的聲明格式如下:
        int getitimer(int which, struct itimerval *value);
        int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
        在使用這兩個調用的進程中加入以下頭檔:
        #include <sys/time.h>

        該系統調用給進程提供了三個計時器,它們各自有其獨有的計時域,當其中任何一個到達,就發送一個相應的信號給進程,並使得計時器重新開始。三個計時器由參數which指定,如下所示:
        TIMER_REAL:按實際時間計時,計時到達將給進程發送SIGALRM信號。
        ITIMER_VIRTUAL:僅當進程執行時才進行計時。計時到達將發送SIGVTALRM信號給進程。
        ITIMER_PROF:當進程執行時和系統為該進程執行動作時都計時。與ITIMER_VIR-TUAL是一對,該計時器經常用來統計進程在使用者態和內核態花費的時間。計時到達將發送SIGPROF信號給進程。

        計時器中的參數value用來指明計時器的時間,其結構如下:
        struct itimerval {
        struct timeval it_interval; /* 下一次的取值 */
        struct timeval it_value; /* 本次的設定值 */
        };

        該結構中timeval結構定義如下:
        struct timeval {
        long tv_sec; /* 秒 */
        long tv_usec; /* 微秒,1秒 = 1000000 微秒*/
        };

        在setitimer 調用中,參數ovalue如果不為空,則其中保留的是上次調用設定的值。計時器將it_value遞減到0時,產生一個信號,並將it_value的值設 定為it_interval的值,然後重新開始計時,如此往復。當it_value設定為0時,計時器停止,或者當它計時到期,而it_interval 為0時停止。調用成功時,返回0;錯誤時,返回-1,並設置相應的錯誤代碼errno:
        EFAULT:參數value或ovalue是無效的指針。
        EINVAL:參數which不是ITIMER_REAL、ITIMER_VIRT或ITIMER_PROF中的一個。

        下面是關於setitimer調用的一個簡單示範,在該例子中,每隔一秒發出一個SIGALRM,每隔0.5秒發出一個SIGVTALRM信號:

        #include <signal.h>
        #include <unistd.h>
        #include <stdio.h>
        #include <sys/time.h>
        int sec;

        void sigroutine(int signo) {
        switch (signo) {
        case SIGALRM:
        printf("Catch a signal -- SIGALRM ");
        break;
        case SIGVTALRM:
        printf("Catch a signal -- SIGVTALRM ");
        break;
        }
        return;
        }

        int main() {
        struct itimerval value,ovalue,value2;
        sec = 5;

        printf("process id is %d ",getpid());
        signal(SIGALRM, sigroutine);
        signal(SIGVTALRM, sigroutine);

        value.it_value.tv_sec = 1;
        value.it_value.tv_usec = 0;
        value.it_interval.tv_sec = 1;
        value.it_interval.tv_usec = 0;
        setitimer(ITIMER_REAL, &value, &ovalue);

        value2.it_value.tv_sec = 0;
        value2.it_value.tv_usec = 500000;
        value2.it_interval.tv_sec = 0;
        value2.it_interval.tv_usec = 500000;
        setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

        for (;;) ;
        }

        該例子的螢幕拷貝如下:

        localhost:~$ ./timer_test
        process id is 579
        Catch a signal – SIGVTALRM
        Catch a signal – SIGALRM
        Catch a signal – SIGVTALRM
        Catch a signal – SIGVTALRM
        Catch a signal – SIGALRM
        Catch a signal –GVTALRM

三、參考代碼

參考 1.

#include<stdio.h>

 

char buf[]={"check lock!\n"};

main()

{

        int i,p1,p2,fd;

        fd=creat("lock.dat",0644);

        write(fd,buf,20);

        while((p1=fork())==-1);

        if(p1==0)

        {

                lockf(fd,1,0);

                for (i=1;i<=3;i++)

                        printf("child1!\n");

                lockf(fd,0,0);

        }

        else{while((p2=fork())==-1);

        if (p2==0)

        {

                lockf(fd,1,0);

                for (i=1;i<=4;i++)

                        printf("child2!\n");

                lockf(fd,0,0);

        }

        else printf("parrent!\n");

        }

        close(fd);

}

 

參考 2

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

 

int waite;

 

static void start(){

   waite=0;

}

 

//自訂中斷調用函數

static void waiting(){

   while(waite==1);

}

 

main(){

   int pid1,pid2;

   while((pid1=fork())==-1);           

   if(pid1>0){

      printf("chilld process 1 is %d\n",pid1);

      while((pid2=fork())==-1);

      if(pid2>0){

         printf("child process 2 is %d\n",pid2);

         printf("please press 'delete'\n");

         waite=1;

         if(signal(SIGUSR1,start)==SIG_ERR);

         else{

            alarm(5);

            signal(SIGALRM,start);//alarm函數使用的信號

         }

         waiting();

         kill(pid1,16);//向child 1 子進程發送16號中斷

         kill(pid2,17);//向child 2 子進程發送17號中斷

         wait(0);//等待兩個子進程結束

         wait(0);

         printf("parent process is killed\n");

         exit(0);

      }

      else{

         waite=1;

         signal(17,start);//接受父進程發送的17號中斷,調用信號中斷函數start()

         waiting();

         printf("child 2 is killed\n");

         exit(0);

      }

   }

   else{

     waite=1;

     signal(16,start);//接受父進程發送的16號中斷,調用信號中斷函數start()

     waiting();

     printf("child 1 is killed\n");

     exit(0);

   }

}

 

參考三

#include <stdio.h>

#include <signal.h>

 

int main()

{

int i,j,stop();

signal(SIGINT,stop);

if(i=fork())

{

        if(j=fork())

        {

                //signal(SIGINT,SIG_IGN);

                sleep(10);

                kill(i,15);

                kill(j,16);

                wait(0);

                wait(0);

                printf("Parent process is killed!\n");

        }

        else {

                signal(16,SIG_IGN);

                sleep(10);

                //signal(16,stop);

                printf("Child process 3 is killed!\n");

                exit(0);

        }     

}

else {

        signal(15,SIG_IGN);

        sleep(10);

        //signal(15,stop);

        printf("Child process 1 is killed!\n");

        exit(0);

}

}

 

stop()

{

//printf("del key is got!\n");

}

 

 

參考四

#include <stdio.h>

#include <unistd.h>

#include <stdio.h>

#include <signal.h>

 

int pid1,pid2;

 

main()

{

int fd[2];

char OutPipe[100],InPipe[100];

pipe(fd);

for(;;)

{

        while((pid1=fork())==-1);

        if(pid1 == 0)

        {

                lockf(fd[1],1,0);

                sprintf(OutPipe,"Child process 1 is sending message!\n");

                write(fd[1],OutPipe,50);

                sleep(3);

                lockf(fd[1],0,0);

                exit(0);

        }

        else {

                while((pid2=fork())==-1);

                if(pid2 == 0)

                {

                        lockf(fd[1],1,0);

                        sprintf(OutPipe,"Child process 2 is sending message!\n");

                        write(fd[1],OutPipe,50);

                        sleep(3);

                        lockf(fd[1],0,0);

                }

                else {

                        wait(0);

                        read(fd[0],InPipe,50);

                        printf("%s\n",InPipe);

                }

        }

}

}

 















轉載自:http://myblog-maurice.blogspot.com/2011/12/linux-signal.html
















 

 


















(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(382)

  • 個人分類:電腦資訊
▲top
  • 1月 12 週一 201516:35
  • Shell Script 字串合併

[root@192 ~]# cat ./test
#! /bin/bash
A="a b c d"
B="c d e f"
C=${A}"---"${B}
echo "$C"
(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(15,793)

  • 個人分類:電腦資訊
▲top
  • 1月 12 週一 201515:35
  • LINUX內核中Netfilter Hook的使用

LINUX內核中Netfilter Hook的使用 作者:JuKevin
 
Hook是Linux Netfilter中重要技術,使用hook可以輕鬆開發內核下的多種網絡處理程序。下面簡單介紹一下hook及其使用。
1.      hook相關數據結構
 
struct nf_hook_ops
{
       struct list_head list;
 
       /* User fills in from here down. */
       nf_hookfn *hook;
       struct module *owner;
       int pf;
       int hooknum;
      
       /* Hooks are ordered in ascending priority. */
       int priority;
};
 
主要成員介紹
int pf; 協議家族類型
int hooknum 為hook執行點,它表示在報文處理的具體什麼階段執行hook函數。
Linux有以下幾種執行點:
NF_IP_PRE_ROUTING          在報文作路由以前執行;
NF_IP_FORWARD                  在報文轉向另一個NIC以前執行;
NF_IP_POST_ROUTING       在報文流出以前執行;
NF_IP_LOCAL_IN                 在流入本地的報文作路由以後執行;
NF_IP_LOCAL_OUT             在本地報文做流出路由前執行。
 
nf_hookfn *hook; 為hook處理回調函數。其定義為:
typedef unsigned int nf_hookfn(
unsigned int hooknum,        //hook執行點
struct sk_buff **skb, //sk buffer數據
const struct net_device *in, //輸入設備
const struct net_device *out, //輸出設備
int (*okfn)(struct sk_buff *) //
)
 
nf_hookfn執行後需要返回以下返回值:
NF_ACCEPT:  繼續正常的報文處理;
NF_DROP:      將報文丟棄;
NF_STOLEN:  由鉤子函數處理了該報文,不要再繼續傳送;
NF_QUEUE:    將報文入隊,通常交由用戶程序處理;
NF_REPEAT:   再次調用該鉤子函數。
 
最後一個參數為hook優先級,內核定義了以下多種優先級:
enum nf_ip_hook_priorities       //include/linux/netfilter_ipv4.h
{
  NF_IP_PRI_FIRST = INT_MIN,
  NF_IP_PRI_CONNTRACK = -200,
  NF_IP_PRI_MANGLE = -150,
  NF_IP_PRI_NAT_DST = -100,
  NF_IP_PRI_FILTER = 0,
  NF_IP_PRI_NAT_SRC = 100,
  NF_IP_PRI_LAST = INT_MAX,
};
 
2.      hook註冊/註銷
 
註冊和註銷函數使用起來非常簡單,我們來看一下它們的函數原型:
 
單個hook註冊和註銷函數
int nf_register_hook(struct nf_hook_ops *reg);         //net/netfilter/core.c
void nf_unregister_hook(struct nf_hook_ops *reg);
 
多個hook註冊和註銷函數
int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
 
3.      一個使用hook來監聽主機ICMP報文的簡單內核模塊程序
 
#include
#include
#include
#include
#include
#include
#include
#include
 
static unsigned int icmp_srv(unsigned int hook,
                                               struct sk_buff **pskb,
                                               const struct net_device *in,
                                               const struct net_device *out,
                                               int (*okfn)(struct sk_buff *)
                                               )
{
       //printk(KERN_INFO"hook_icmp::icmp_srv()\n");
       struct iphdr *iph = (*pskb)->nh.iph;
      
       if(iph->protocol == IPPROTO_ICMP)
       {
              printk(KERN_INFO"hook_icmp::icmp_srv: receive ICMP packet\n");
              printk(KERN_INFO"src: ");
       }
      
       return NF_ACCEPT;
}
 
static struct nf_hook_ops icmpsrv_ops =
{
       .hook = icmp_srv,
       .pf = PF_INET,
       .hooknum = NF_IP_PRE_ROUTING,
       .priority = NF_IP_PRI_FILTER -1,
};
 
static int __init init_hook_icmp(void)
{
       return nf_register_hook(&icmpsrv_ops);
}
 
static void __exit fini_hook_icmp(void)
{
       nf_unregister_hook(&icmpsrv_ops);
}
 
MODULE_LICENSE("GPL");
 
module_init(init_hook_icmp);
module_exit(fini_hook_icmp);
 
編譯改模塊之後,加載該模塊,之後可以在DOS下用ping命令來測試。
在linux中用dmesg查看,可以看到收到的icmp報文
hook_icmp::icmp_srv: receive ICMP packet
hook_icmp::icmp_srv: receive ICMP packet
hook_icmp::icmp_srv: receive ICMP packet
hook_icmp::icmp_srv: receive ICMP packet
------------------------------------------------------------------------------------


2.6內核中netfilter hook點一覽


本文檔的Copyleft歸yfydz所有,使用GPL發佈,可以自由拷貝,轉載,轉載時請保持文檔的完整性,嚴禁用於任何商業用途。
msn: yfydz_no1@hotmail.com
來源:http://yfydz.cublog.cn


1. 5個掛接點

以下內核代碼版本2.6.17.11。

1.1 PREROTING

/* net/ipv4/ip_input.c */

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
......
 return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
         ip_rcv_finish);
......
}


1.2 INPUT

/* net/ipv4/ip_input.c */

int ip_local_deliver(struct sk_buff *skb)
{
......
 return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,
         ip_local_deliver_finish);
}


1.3 FORWARD

/* net/ipv4/ip_forward.c */

int ip_forward(struct sk_buff *skb)
{
......
 return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,
         ip_forward_finish);
......
}


1.4 OUTPUT

/* net/ipv4/ip_output.c */
int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
     u32 saddr, u32 daddr, struct ip_options *opt)
{
......
 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
         dst_output);
}

int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
{
......
 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
         dst_output);
......
}

int ip_push_pending_frames(struct sock *sk)
{
......
 /* Netfilter gets whole the not fragmented skb. */
 err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
        skb->dst->dev, dst_output);
......
}

1.5 POSTROUTING


/* net/ipv4/ip_output.c */

int ip_output(struct sk_buff *skb)
{
 struct net_device *dev = skb->dst->dev;

 IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);

 skb->dev = dev;
 skb->protocol = htons(ETH_P_IP);

 return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
              ip_finish_output,
       !(IPCB(skb)->flags & IPSKB_REROUTED));
}


2. 每個掛接點所掛接的hook操作


只考慮是AF_INET協議族的掛接點,以下各點的hook操作按執行順序排序,優先級數值越小,級別越高,執行順序越靠前。

如果用戶可以通過iptables規則進行控制的處理點稱為用戶可控,否則為不可控。


2.1 PREREOUTING


/* net/bridge/br_netfilter.c */
// 這個hook點只丟棄skb結構中設置橋參數但沒有相關橋標誌的包
// 用戶不可控
 { .hook = ip_sabotage_in,
   .owner = THIS_MODULE,
   .pf = PF_INET,
   .hooknum = NF_IP_PRE_ROUTING,
// 優先級最高
   .priority = NF_IP_PRI_FIRST,
        },


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 這個hook點完成分片重組,以後處理過程中的包都是非分片包
// 直到發送出去重新分片。注意2.6重組後的分片包並不進行線性
// 化,所以邏輯上應該連在一起的兩字節數據可能分屬不同的頁,
// 存儲是不連續的
// 該點操作用戶不可控
 {
  .hook  = ip_conntrack_defrag,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_PRE_ROUTING,
// 優先級為-400
  .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
 },


/* net/ipv4/netfilter/iptable_raw.c */
// 這個hook點為raw表,提供對收到的數據包在連接跟蹤前進行處理的手段
// 該點用戶可加載iptables規則進行控制
 {
  .hook = ipt_hook,
  .pf = PF_INET,
  .hooknum = NF_IP_PRE_ROUTING,
// 優先級為-300
  .priority = NF_IP_PRI_RAW,
  .owner = THIS_MODULE,
 },


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 這個hook點完成連接跟蹤,為每個skb找到所屬連接(ESTABLISHED, REPLY)
// 或新建連接(NEW, RELATED)
// 該點操作用戶不可控
 {
  .hook  = ip_conntrack_in,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_PRE_ROUTING,
// 優先級為-200
  .priority = NF_IP_PRI_CONNTRACK,
 },


/* net/ipv4/netfilter/iptable_mangle.c */
// 這個hook點為mangle表,提供對收到的數據包進行修改的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_route_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_PRE_ROUTING,
// 優先級為-150
  .priority = NF_IP_PRI_MANGLE,
 },

 

/* net/ipv4/netfilter/ip_nat_standalone.c */
// 該hook點對剛收到本機的skb包進行目的NAT操作
// 用戶規則可控,nat表,但規則只對NEW包進行處理,後續包自動處理
 {
  .hook  = ip_nat_in,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_PRE_ROUTING,
// 優先級為-100
  .priority = NF_IP_PRI_NAT_DST,
 },


/* net/sched/sch_ingress.c */
// 該hook點對j進入本機的skb包進行排隊處理,QoS操作
// 用戶不可控
static struct nf_hook_ops ing_ops = {
 .hook           = ing_hook,
 .owner  = THIS_MODULE,
 .pf             = PF_INET,
 .hooknum        = NF_IP_PRE_ROUTING,
// 優先級為1
 .priority       = NF_IP_PRI_FILTER + 1,
};

 

2.2 INPUT


/* net/ipv4/netfilter/iptable_mangle.c */
// 這個hook點為mangle表,提供對收到的數據包進行修改的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_route_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_IN,
// 優先級為-150
  .priority = NF_IP_PRI_MANGLE,
 },


/* net/ipv4/netfilter/iptable_filter.c */
// 這個hook點為filter表,提供對進入本機的數據包進行過濾的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_IN,
// 優先級為0
  .priority = NF_IP_PRI_FILTER,
 },


/* net/ipv4/netfilter/ip_nat_standalone.c */
// 對進入本機的skb包進行源NAT操作
// 用戶規則可控,nat表,但規則只對NEW包進行處理,後續包自動處理
 {
  .hook  = ip_nat_fn,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_IN,
// 優先級為100
  .priority = NF_IP_PRI_NAT_SRC,
 },


/* net/ipv4/ipvs/ip_vs_core.c */
// 該hook點對進入本機的skb包均衡分配
// 用戶不可控
static struct nf_hook_ops ip_vs_in_ops = {
 .hook  = ip_vs_in,
 .owner  = THIS_MODULE,
 .pf  = PF_INET,
 .hooknum        = NF_IP_LOCAL_IN,
 .priority       = 100,
};


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 該hook點對進入本機的skb包完成對連接跟蹤的help,也就是
// 多連接協議中對子連接的處理
// 用戶不可控
 {
  .hook  = ip_conntrack_help,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_IN,
// 優先級為INT_MAX-2,相當低
  .priority = NF_IP_PRI_CONNTRACK_HELPER,
 },


/* net/ipv4/netfilter/ip_nat_standalone.c */
// 對進入本機的skb包進行TCP序列號調整操作,主要是因為跟蹤多連接協議時
// 修改了數據包內容可能導致數據包長度發生變化,相應序列號和確認號需要
// 自動調整
// 用戶規則不可控
 {
  .hook  = ip_nat_adjust,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_IN,
// 優先級為INR_MAX-1,相當低
  .priority = NF_IP_PRI_NAT_SEQ_ADJUST,
 },

 

/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 該hook點對進入本機的skb包完成最後的確認,只對NEW包處理
// 確認NEW的連接信息在當前的連接表中是不存在的
// 用戶不可控
 {
  .hook  = ip_confirm,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_IN,
// 優先級為INT_MAX,最低
  .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
 },


2.3 FORWARD


/* net/bridge/br_netfilter.c */
// 這個hook點對由橋網卡轉發的skb包設置橋信息和物理網卡等信息
// 該函數可能會返回NF_STOP不進行後續hook點的處理
// 用戶不可控
 { .hook = ip_sabotage_out,
   .owner = THIS_MODULE,
   .pf = PF_INET,
   .hooknum = NF_IP_FORWARD,
// 優先級為-175
   .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD,
        },

/* net/ipv4/netfilter/iptable_mangle.c */
// 這個hook點為mangle表,提供對收到的數據包進行修改的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_route_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_FORWARD,
// 優先級為-150
  .priority = NF_IP_PRI_MANGLE,
 },


/* net/ipv4/netfilter/iptable_filter.c */
// 這個hook點為filter表,提供對轉發的數據包進行過濾的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_FORWARD,
// 優先級為0
  .priority = NF_IP_PRI_FILTER,
 },


/* net/ipv4/ipvs/ip_vs_core.c */
// 該hook點對轉發的skb包均衡分配前處理ICMP異常
// 用戶不可控
static struct nf_hook_ops ip_vs_forward_icmp_ops = {
 .hook  = ip_vs_forward_icmp,
 .owner  = THIS_MODULE,
 .pf  = PF_INET,
 .hooknum        = NF_IP_FORWARD,
 .priority       = 99,
};

/* net/ipv4/ipvs/ip_vs_core.c */
// 該hook點對轉發的skb包均衡分配
// 用戶不可控
static struct nf_hook_ops ip_vs_out_ops = {
 .hook  = ip_vs_out,
 .owner  = THIS_MODULE,
 .pf  = PF_INET,
 .hooknum        = NF_IP_FORWARD,
 .priority       = 100,
};

 

3.4 OUTPUT


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 這個hook點對自身發出的包完成分片重組,以後處理過程中的包都是非分片包
// 直到最後發送出去重新分片。注意2.6重組後的分片包並不進行線性
// 化,所以邏輯上應該連在一起的兩字節數據可能分屬不同的頁,
// 存儲是不連續的
// 該點操作用戶不可控
 {
  .hook  = ip_conntrack_defrag,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_OUT,
// 優先級為-400
  .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
 },


/* net/ipv4/netfilter/iptable_raw.c */
// 這個hook點為raw表,提供對本機發出數據包在連接跟蹤前進行處理的手段
// 該點用戶可加載iptables規則進行控制
 {
  .hook = ipt_hook,
  .pf = PF_INET,
  .hooknum = NF_IP_LOCAL_OUT,
// 優先級為-300
  .priority = NF_IP_PRI_RAW,
  .owner = THIS_MODULE,
 },


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 這個hook點對自身發出的包完成連接跟蹤,為每個skb找到所屬連接
// (ESTABLISHED, REPLY)或新建連接(NEW, RELATED)
// 該點操作用戶不可控
 {
  .hook  = ip_conntrack_local,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_OUT,
// 優先級為-200
  .priority = NF_IP_PRI_CONNTRACK,
 },

/* net/ipv4/netfilter/iptable_mangle.c */
// 這個hook點為mangle表,提供對收到的數據包進行修改的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_local_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_OUT,
// 優先級為-150
  .priority = NF_IP_PRI_MANGLE,
 },

 

/* net/ipv4/netfilter/ip_nat_standalone.c */
// 對本機發出的skb包進行目的NAT操作
// 用戶規則可控,nat表,但規則只對NEW包進行處理,後續包自動處理
 {
  .hook  = ip_nat_local_fn,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_OUT,
// 優先級為-100
  .priority = NF_IP_PRI_NAT_DST,
 },


/* net/bridge/br_netfilter.c */
// 這個hook點對由橋網卡發出的skb包設置橋信息和物理網卡等信息
// 該函數會返回NF_STOP,提前終止檢查而返回
// 用戶不可控
 { .hook = ip_sabotage_out,
   .owner = THIS_MODULE,
   .pf = PF_INET,
   .hooknum = NF_IP_LOCAL_OUT,
// 優先級為-50
   .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT,
         },


/* net/ipv4/netfilter/iptable_filter.c */
// 這個hook點為filter表,提供對本機發出的數據包進行過濾的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_local_out_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_LOCAL_OUT,
// 優先級為0
  .priority = NF_IP_PRI_FILTER,
 },

 


2.5 POSTROUTING


/* net/bridge/br_netfilter.c */
// 這個hook點對由橋網卡發出的skb包設置橋信息和物理網卡等信息
// 該函數會返回NF_STOP,提前終止檢查而返回
// 用戶不可控
 { .hook = ip_sabotage_out,
   .owner = THIS_MODULE,
   .pf = PF_INET,
   .hooknum = NF_IP_POST_ROUTING,
// 優先級最高
   .priority = NF_IP_PRI_FIRST, },


/* net/ipv4/netfilter/iptable_mangle.c */
// 這個hook點為mangle表,提供對收到的數據包進行修改的處理
// 該點用戶可加載iptables規則進行控制
 {
  .hook  = ipt_route_hook,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_POST_ROUTING,
// 優先級為-150
  .priority = NF_IP_PRI_MANGLE,
 },


/* net/ipv4/ipvs/ip_vs_core.c */
// 該hook點對IPVS本身的控制包直接返回NF_STOP不進行後續hook點處理
// 用戶不可控
static struct nf_hook_ops ip_vs_post_routing_ops = {
 .hook  = ip_vs_post_routing,
 .owner  = THIS_MODULE,
 .pf  = PF_INET,
 .hooknum        = NF_IP_POST_ROUTING,
// 優先級為99
 .priority       = NF_IP_PRI_NAT_SRC-1,
};


/* net/ipv4/netfilter/ip_nat_standalone.c */
// 對本機發出的skb包進行源NAT操作
// 用戶規則可控,nat表,但規則只對NEW包進行處理,後續包自動處理
 {
  .hook  = ip_nat_out,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_POST_ROUTING,
// 優先級為100
  .priority = NF_IP_PRI_NAT_SRC,
 },


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 該hook點對轉發的skb包完成對連接跟蹤的help,也就是
// 多連接協議中對子連接的處理
// 用戶不可控
 {
  .hook  = ip_conntrack_help,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
// 優先級為INT_MAX-2,相當低
  .hooknum = NF_IP_POST_ROUTING,
  .priority = NF_IP_PRI_CONNTRACK_HELPER,
 },


/* net/ipv4/netfilter/ip_nat_standalone.c */
// 對發出本機的skb包進行TCP序列號調整操作,主要是因為跟蹤多連接協議時
// 修改了數據包內容可能導致數據包長度發生變化,相應序列號和確認號需要
// 自動調整
// 用戶規則不可控
 {
  .hook  = ip_nat_adjust,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_POST_ROUTING,
// 優先級為INR_MAX-1,相當低
  .priority = NF_IP_PRI_NAT_SEQ_ADJUST,
 },


/* net/ipv4/netfilter/ip_conntrack_standalone.c */
// 該hook點對進入本機的skb包完成最後的確認,只對NEW包處理
// 確認NEW的新連接信息在當前的連接表中是不存在的
// 用戶不可控
 {
  .hook  = ip_confirm,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum = NF_IP_POST_ROUTING,
// 優先級為INT_MAX,最低
  .priority = NF_IP_PRI_CONNTRACK_CONFIRM,
 },


3. 結論


由此可見,即使內核不支持bridge, ipvs和sched,一個轉發包通過netfilter時也會經過12個處理點的處理,任何一點的拒絕都會使該包丟棄,在各點的控制處理功能可以高度集 中,像流水線的各個環節一樣。如果能用多核處理器能讓比較費資源的點單獨跑一個核,各個核的處理結果進行流水線,系統效率的提升肯定會很高,可惜這種 AMP處理還是"Mission impossible",當前的SMP處理方式只會使netfilter架構效率很低,什麼時候可以把「im」去掉還要等待。

 

原文地址:http://blog.chinaunix.net/uid-30483626-id-5195453.html


(繼續閱讀...)
文章標籤

lyt0112 發表在 痞客邦 留言(0) 人氣(2,936)

  • 個人分類:電腦資訊
▲top
  • 1月 12 週一 201515:05
  • Linux netfilter源碼分析

Linux netfilter源碼分析(1)
  • IP報文的接收到hook函數的調用

  • 1.1  ip_input.c    ip_rcv()函數
    以接收到的報文為例,類似的還有ip_forward(ip_forward.c)和ip_output(ip_output.c)
    int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
    {

        struct iphdr *iph;   //定義一個ip報文的數據報頭
        u32 len;
        if (skb->pkt_type == PACKET_OTHERHOST)
           goto drop; 
    //數據包不是發給我們的
        IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); //收到數據包統計量加1
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
       {
    /* 如果數據報是共享的,則複製一個出來,此時複製而出的已經和socket脫離了關係 */
          IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
          goto out;
       }

       if (!pskb_may_pull(skb, sizeof(struct iphdr)))
         goto inhdr_error; 
    //對數據報的頭長度進行檢查,
     
       iph = skb->nh.iph;  //取得數據報的頭部位置
      if (iph->ihl < 5 || iph->version != 4)  //版本號或者頭長度不對,
        goto inhdr_error; //頭長度是以4字節為單位的,所以5表示的是20字節
      if (!pskb_may_pull(skb, iph->ihl*4))
        goto inhdr_error;

     
      if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
         goto inhdr_error;
    //檢查報文的檢驗和字段
      len = ntohs(iph->tot_len);
     if (skb->len < len || len < (iph->ihl*4))
        goto inhdr_error;
    //整個報文長度不可能比報頭長度小
     if (pskb_trim_rcsum(skb, len))
     { //對數據報進行裁減,這樣可以分片發送過來的數據報不會有重複數據
      IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
      goto drop;
     }

       return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
             ip_rcv_finish);
    //通過回調函數調用ip_rcv_finish
    inhdr_error:
     IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
    drop:
            kfree_skb(skb);
    //丟掉數據報
    out:
            return NET_RX_DROP;
    }

     
     
     
    1.2  include/linux/netfilter.h  NF_HOOK
     
    #ifdef CONFIG_NETFILTER_DEBUG
    #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                     \
     nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN)
    #define NF_HOOK_THRESH nf_hook_slow
    #else
    #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                     \
    (list_empty(&nf_hooks[(pf)][(hook)])                                  \
     ? (okfn)(skb)                                                       \
     : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN))
    #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)       \
    (list_empty(&nf_hooks[(pf)][(hook)])                                  \
     ? (okfn)(skb)                                                       \
     : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), (thresh)))
    #endif
     
    /*    如果nf_hooks[PF_INET][NF_IP_FORWARD]所指向的鏈表為空(即該鉤子上沒有掛處理函數),則直接調用okfn;否則,則調用net/core/netfilter.c::nf_hook_slow()轉入Netfilter的處理。  */
     
     
    1.3  net/core/netfilter.c  nf_kook_slow()函數
     
    int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
                     struct net_device *indev,
                     struct net_device *outdev,
                     int (*okfn)(struct sk_buff *),
                     int hook_thresh)
    {
            struct list_head *elem;
            unsigned int verdict;
            int ret = 0;
            rcu_read_lock();
            /*
    取得對應的鏈表首部*/
            elem = &nf_hooks[pf][hook];
    next_hook:
            /*
    調用對應的鉤子函數*/
            verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
                                 outdev, &elem, okfn, hook_thresh);

            /*判斷返回值,做相應的處理*/
    if (verdict == NF_ACCEPT || verdict == NF_STOP) {
             ret = 1;    /*
    前面提到過,返回1,則表示裝繼續調用okfn函數指針*/
             goto unlock;
        } else if (verdict == NF_DROP) {
             kfree_skb(*pskb);                /*
    刪除數據包,需要釋放skb*/
              ret = -EPERM;
        } else if (verdict == NF_QUEUE) {
              NFDEBUG("nf_hook: Verdict = QUEUE.\n");
                  if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn))
                   goto next_hook;
         }
    unlock:
            rcu_read_unlock();
            return ret;
    }

     
    1.4   net/core/netfilter.c   nf_iterate()函數
     
    static unsigned int nf_iterate(struct list_head *head,
                                struct sk_buff **skb,
                                int hook,
                                const struct net_device *indev,
                                const struct net_device *outdev,
                                struct list_head **i,
                                int (*okfn)(struct sk_buff *),
                                int hook_thresh)
    {
           /*
            * The caller must not block between calls to this
            * function because of risk of continuing from deleted element.
            */
    /* 依次調用指定hook點下的所有nf_hook_ops->(*hook)函數,這些nf_hook_ops裡有filter表註冊的,有mangle表註冊的,等等。
    list_for_each_continue_rcu函數是一個for循環的宏,當調用結點中的hook函數後,根據返回值進行相應處理。如果hook函數的返回值是NF_QUEUE,NF_STOLEN,NF_DROP時,函數返回該值;如果返回值是NF_REPEAT時,則跳到前一個結點繼續處理;如果是其他值,由下一個結點繼續處理。如果整條鏈表處理完畢,返回值不是上面四個值,則返回NF_ACCEPT。*/
           list_for_each_continue_rcu(*i, head) {
                  struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
     
                  if (hook_thresh > elem->priority)
                         continue;
     
                  switch (elem->hook(hook, skb, indev, outdev, okfn)) {
                  case NF_QUEUE:
                         return NF_QUEUE;
     
                  case NF_STOLEN:
                         return NF_STOLEN;
     
                  case NF_DROP:
                         return NF_DROP;
     
                  case NF_REPEAT:
                         *i = (*i)->prev;
                         break;
                  }
           }
           return NF_ACCEPT;
    }
     
    轉貼自:http://alexanderlaw.blog.hexun.com/8960896_d.html
    (繼續閱讀...)
    文章標籤

    lyt0112 發表在 痞客邦 留言(0) 人氣(264)

    • 個人分類:電腦資訊
    ▲top
    • 1月 12 週一 201514:32
    • iptables的String模組

    string模組是Netfilter/iptables提供的一個字串比對模組,使用者可用來比對Layer7應用層上任何的字串,
    本文就是利用此模組來比對HTTP通訊協定上的字串以達到限制網站存取的目的,所提供的參數如下所示:
    --from:從那個位元處開始比對。
    --to:從那個位元處結束比對。
    --algo:使用來比對的演算法,提供了Boyer-Moore (bm)及Knuth-Pratt-Morris(kmp)比對。
    --icase:比對是否要區分大小寫,0代表不區分,1代表區分大小寫。
    --string“比對文字”:欲比對的字串。
    --hex-string“16進制比對文字”:欲比對的16進制 字串。
    以下範例表示,若符合"比對文字"就阻擋該連線:
    (繼續閱讀...)
    文章標籤

    lyt0112 發表在 痞客邦 留言(0) 人氣(707)

    • 個人分類:電腦資訊
    ▲top
    12»

    個人資訊

    lyt0112
    暱稱:
    lyt0112
    分類:
    休閒旅遊
    好友:
    累積中
    地區:

    最新文章

    • 桃園蘆竹五酒桶山O型 A10機捷山鼻站
    • IPv4 Subnet Mask IP Range
    • 日光溫泉會館-花見西餐廳下午茶
    • 彰化-大村-進昌咖啡烘焙館
    • 新北市-九份-黃金博物館 老街
    • 台中-后里-泰安國小旁落羽松
    • __DATE__ 和 __TIME__ 編譯時報錯
    • Linux 無法開機常見的解法 acpi=off noapic
    • 用ipset配置linux防火牆
    • 利用 ipset 封禁大量 IP

    熱門文章

    • (15,793)Shell Script 字串合併
    • (7,107)iptables四個表與五個鏈間的關係
    • (4,934)linux 網絡虛擬化: macvlan
    • (2,936)LINUX內核中Netfilter Hook的使用
    • (2,805)Linux 無法開機常見的解法 acpi=off noapic
    • (2,669)利用 ipset 封禁大量 IP
    • (1,934)Linux下/proc裡面的arp_announce和arp_ignore
    • (1,202)網絡虛擬化技術(二): TUN/TAP MACVLAN MACVTAP
    • (382)Linux 信號signal處理機制
    • (156)彰化-大村-進昌咖啡烘焙館

    文章精選

    參觀人氣

    • 本日人氣:
    • 累積人氣:

    文章分類

    • 電腦資訊 (14)
    • 吃吃喝喝 (1)
    • 國內旅遊 (4)
    • 未分類文章 (1)

    最新留言

      文章搜尋

      留言板