1. 程式人生 > >iptables深入解析-filter應用篇

iptables深入解析-filter應用篇

     上一篇文章分析了iptables程式碼下發運作的流程細節,篇幅有限還有很多需要補充.關於netfilter的框架網上已經被講爛了,框架很簡單,但是實現卻不簡單.但不論什麼都要最終歸到實際應用上,才能體現其價值. 
    下面我們就以iptables1.4.21  ubuntu14 32位  核心版本 3.13.0為環境來開發一個最常規的擴充套件應用.
    首先下載iptables原始碼:http://www.netfilter.org (這個網站有很多東西,可以好好看看)
    關於linux kernel netfilter開啟的配置,這裡不多說,預設核心已經配置好了.(當然對於ubuntu14 系統預設把netfilter大部分都編譯成了核心模組,需要什麼自己手動安裝即可)
先說說編譯iptables,很簡單 看看裡面的說明文件即可,例INSTALL:
$./configure
$make
$make install 

./configure 還可以支援一些選項引數 ,裡面都有說明。例子如下:
./configure --prefix=/home/iptables      --host=arm-linux  //  host可以不指定,自動判定,預設就是x86
這裡還要補充點知識:動作的說明:
iptables動作---------DROP、ACCEPT、REJECT 
◆ACCEPT  
一旦包滿足了指定的匹配條件,就會被ACCEPT,並且不會再去匹配當前鏈中的其他規則或同一個表內的其他規則,但它還要通過其他表中的鏈
◆DROP 
如果包符合條件,這個target就會把它丟掉,也就是說包的生命到此結束,不會再向前走一步,效果就是包被阻塞了。在某些情況下,這個target會引起意外的結果,因為它不會向傳送者返回任何資訊,也不會向路由器返回資訊,這就可能會使連線的另一方的sockets因苦等迴音而亡:)  
解決這個問題的較好的辦法是使用REJECT target,(注:因為它在丟棄包的同時還會向傳送者返回一個錯誤資訊,這樣另一方就能正常結束),尤其是在阻止埠掃描工具獲得更多的資訊時,可以隱蔽被過濾掉的埠等等(譯者注:因為掃描工具掃描一個埠時,如果沒有返回資訊,一般會認為埠未開啟或被防火牆等裝置過濾掉了)。還要注意如果包在子鏈中被DROP了,那麼它在主鏈裡也不會再繼續前進,不管是在當前的表還是在其他表裡。
◆REJECT 
REJECT和DROP基本一樣,區別在於它除了阻塞包之外,還向傳送者返回錯誤資訊。現在,此target還只能用在INPUT、FORWARD、OUTPUT和它們的子鏈裡,而且包含 REJECT的鏈也只能被它們呼叫,否則不能發揮作用。它只有一個選項,是用來控制返回的錯誤資訊的種類的。

還有其他的動作:
LOG                           用來記錄與資料包相關的資訊 
MARK                          設定mark值,這個值是一個無符號的整數 
MASQUERADE                    和SNAT的作用相同,區別在於它不需要指定--to-source 
SNAT                          源網路地址轉換 
DNAT                          目的網路地址轉換 
REDIRECT                      轉發資料包一另一個埠 
REJECT                        REJECT和DROP都會將資料包丟棄,區別在於REJECT除了丟棄資料包外,還向傳送者返回錯誤資訊 
RETURN                        使資料包返回上一層 
TOS                           用來設定IP頭部中的Type Of Service欄位 
TTL                           用於修改IP頭部中Time To Live欄位的值 
ULOG                          ULOG可以在使用者空間記錄被匹配的包的資訊,這些資訊和整個包都會通過netlink socket被多播 
QUEUE                         為使用者空間的程式或應用軟體管理包佇列 
MIRROR                        顛倒IP頭部中的源目地址,然後再轉發包

先一個實際的命令應用:
IPT -A INPUT -m pkttype –pkt-type broadcast -j REJECT 
這裡我們自己註冊一個match 傳遞自己的引數並解析處理。
功能是禁止大於特定長度的ip報文通過 size由我們指定。
需要兩個部分的工作
1.使用者空間match的註冊
2.核心空間match的註冊
根據程式碼裡pkttype的實際例子作為參考,很快我們就能幹一票了.
需要修改的檔案:
使用者空間
Xt_pktsize.c   // 路徑extensions下
Xt_pktsize.h   // 路徑 include/linux/netfilter/
核心:這裡編譯為模組的方式
Xt_pktsize.c   
Xt_pktsize.h

註冊match當然首先要初始化它各個節點的元素
使用者空間程式碼如下:
xt_pktsize.h

點選(此處

)摺疊或開啟

  1. #ifndef _XT_PKTSIZE_H
  2. #define _XT_PKTSIZE_H
  3. struct xt_pktsize_info {
  4.     int    pktsize;
  5.     int    invert;
  6. };
  7. #endif /*_XT_PKTSIZE_H*/
xt_pktsize.c

點選(此處)摺疊或開啟

  1. /*
  2.  * Shared library add-on to iptables to match
  3.  * packets by their size
  4.  *
  5.  */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <
    xtables.h>
  9. #include <linux/if_packet.h>
  10. #include <linux/netfilter/xt_pktsize.h>
  11. enum {
  12.     O_pktsize = 0,
  13. };
  14. struct pktsizes {
  15.     const char *name;
  16.     unsigned char pktsize;
  17.     unsigned char printhelp;
  18.     const char *help;
  19. };
  20. static void print_types(void)
  21. {
  22.     unsigned int    i;
  23.     printf("Valid packet sizes:64-65535\n"
    );
  24. }
  25. static void pktsize_help(void)
  26. {
  27.     printf(
  28. "pktsize match options:\n"
  29. "[!] --pkt-size packetsize match packet size\n");
  30.     print_types();
  31. }
  32. static const struct xt_option_entry pktsize_opts[] = {
  33.     {.name = "pkt-size", .id = O_pktsize, .type = XTTYPE_STRING,
  34.      .flags = XTOPT_MAND | XTOPT_INVERT},
  35.     XTOPT_TABLEEND,
  36. };
  37. static void parse_pktsize(const char *pktsize, struct xt_pktsize_info *info)
  38. {
  39.     unsigned int    i,size;
  40.     char *buffer;
  41.             printf("pktsize is %s...\n",pktsize);
  42.             buffer = strdup(pktsize);
  43.             if(!xtables_strtoui(buffer, NULL, &size, 0, UINT16_MAX))
  44.                 xtables_error(PARAMETER_PROBLEM, "Bad packet size '%s'", pktsize);
  45.             info->pktsize=size;
  46.             free(buffer);
  47. }
  48. static void pktsize_parse(struct xt_option_call *cb)
  49. {
  50.     struct xt_pktsize_info *info = cb->data;
  51.     xtables_option_parse(cb);
  52.     parse_pktsize(cb->arg, info);
  53.     if (cb->invert)
  54.         info->invert = 1;
  55. }
  56. static void print_pktsize(const struct xt_pktsize_info *info)
  57. {
  58.     unsigned int    i;
  59.     printf("%d", info->pktsize);    /* in case we didn't find an entry in named-packtes */
  60. }
  61. static void pktsize_print(const void *ip, const struct xt_entry_match *match,
  62.                           int numeric)
  63. {
  64.     const struct xt_pktsize_info *info = (const void *)match->data;
  65.     printf(" pktsize %s= ", info->invert ? "!" : "");
  66.     print_pktsize(info);
  67. }
  68. static void pktsize_save(const void *ip, const struct xt_entry_match *match)
  69. {
  70.     const struct xt_pktsize_info *info = (const void *)match->data;
  71.     printf("%s --pkt-type ", info->invert ? " !" : "");
  72.     print_pktsize(info);
  73. }
  74. static struct xtables_match pktsize_match = {
  75.     .family        = NFPROTO_UNSPEC,
  76.     .name        = "pktsize",
  77.     .version    = XTABLES_VERSION,
  78.     .size        = XT_ALIGN(sizeof(struct xt_pktsize_info)),
  79.     .userspacesize    = XT_ALIGN(sizeof(struct xt_pktsize_info)),
  80.     .help        = pktsize_help,
  81.     .print        = pktsize_print,
  82.     .save        = pktsize_save,
  83.     .x6_parse    = pktsize_parse,
  84.     .x6_options    = pktsize_opts,
  85. };
  86. void _init(void)
  87. {
  88.     xtables_register_match(&pktsize_match);
  89. }
通過程式碼我們看到主要工作就是初始化struct xtables_match,然後註冊而已. 它的核心函式是x6_parse/parse

點選(此處)摺疊或開啟

  1. /* Function which parses command options; returns true if it
  2.            ate an option */
  3.     /* entry is struct ipt_entry for example */
  4.     int (*parse)(int c, char **argv, int invert, unsigned int *flags,
  5.          const void *entry,
  6.          struct xt_entry_match **match);
或者

點選(此處)摺疊或開啟

  1. /* New parser */
  2.     void (*x6_parse)(struct xt_option_call *);
例子中為 pktsize_parse函式,之前我們已經分析過如何呼叫到某一個match的parse函式.主要解析ipt_entry_match裡data(其實就是解析命令引數賦值給它)
除了parse函式還有options,即解析--XXX的引數需要用到的東西,也需要我們去填寫。

下面看看核心部分:
xt_pktsize.h

點選(此處)摺疊或開啟

  1. #ifndef _XT_PKTSIZE_H
  2. #define _XT_PKTSIZE_H
  3. struct xt_pktsize_info {
  4.     int    pktsize;
  5.     int    invert;
  6. };
  7. #endif /*_XT_PKTSIZE_H*/
xt_pktsize.c

點選(此處)摺疊或開啟

  1. #include <linux/module.h>
  2. #include <linux/skbuff.h>
  3. #include <linux/if_ether.h>
  4. #include <linux/if_packet.h>
  5. #include <linux/in.h>
  6. #include <linux/ip.h>
  7. #include <linux/ipv6.h>
  8. //#include <linux/netfilter/xt_pktsize.h>
  9. #include "xt_pktsize.h"
  10. #include <linux/netfilter/x_tables.h>
  11. MODULE_LICENSE("GPL");
  12. MODULE_AUTHOR("jack chen");
  13. MODULE_DESCRIPTION("Xtables: link layer packet size match");
  14. MODULE_ALIAS("ipt_pktsize");
  15. MODULE_ALIAS("ip6t_pktsize");
  16. static bool
  17. pktsize_mt(const struct sk_buff *skb, struct xt_action_param *par)
  18. {
  19.     const struct xt_pktsize_info *info = par->matchinfo;
  20.     u_int32_t size;
  21.     const struct iphdr *iph = ip_hdr(skb);
  22.     size=ntohs(iph->tot_len) - (iph->ihl*4);
  23.     printk("ip data pktsize is %d......,%d..,proto :%x\n",size,info->pktsize,iph->protocol);
  24.     return (info->pktsize < size) ;
  25.     //return 1;
  26. }
  27. static struct xt_match pktsize_mt_reg __read_mostly = {
  28.     .name = "pktsize",
  29.     .revision = 0,
  30.     .family = NFPROTO_UNSPEC,
  31.     .match = pktsize_mt,
  32.     .matchsize = sizeof(struct xt_pktsize_info),
  33.     .me = THIS_MODULE,
  34. };
  35. static int __init pktsize_mt_init(void)
  36. {
  37.     return xt_register_match(&pktsize_mt_reg);
  38. }
  39. static void __exit pktsize_mt_exit(void)
  40. {
  41.     xt_unregister_match(&pktsize_mt_reg);
  42. }
  43. module_init(pktsize_mt_init);
  44. module_exit(pktsize_mt_exit);
這裡我們計算ip報文的有效載荷的長度即ip包的總長度-ip頭的長度
 size=ntohs(iph->tot_len) - (iph->ihl*4);
同樣或許我們還需要判斷協議型別 protocal字等,簡單說幾個常用:
Decimal  Keyword          Protocol                                 References
-------  ---------------  ---------------------------------------  ------------------
1        ICMP             Internet Control Message                 [RFC792]
6        TCP              Transmission Control                     [RFC793]
17       UDP              User Datagram                            [RFC768][JBP]
...
ip報文格式如下:

版本:佔4位(bit),指IP協議的版本號。目前的主要版本為IPV4,即第4版本號,也有一些教育網和科研機構在使用IPV6。在進行通訊時,通訊雙方的IP協議版本號必須一致,否則無法直接通訊。 
首部長度:佔4位(bit),指IP報文頭的長度。最大的長度(即4個bit都為1時)為15個長度單位,每個長度單位為4位元組(TCP/IP標準,DoubleWord),所以IP協議報文頭的最大長度為60個位元組,最短為上圖所示的20個位元組。 
服務型別:佔8位(bit),用來獲得更好的服務。其中的前3位表示報文的優先順序,後面的幾位分別表示要求更低時延、更高的吞吐量、更高的可靠性、更低的路由代價等。對應位為1即有相應要求,為0則不要求。 
總長度:16位(bit),指報文的總長度。注意這裡的單位為位元組,而不是4位元組,所以一個IP報文的的最大長度為65535個位元組。 
標識(identification):該欄位標記當前分片為第幾個分片,在資料報重組時很有用。 
標誌(flag):該欄位用於標記該報文是否為分片(有一些可能不需要分片,或不希望分片),後面是否還有分片(是否是最後一個分片)。 
片偏移:指當前分片在原資料報(分片前的資料報)中相對於使用者資料欄位的偏移量,即在原資料報中的相對位置。 
生存時間:TTL(Time to Live)。該欄位表明當前報文還能生存多久。每經過1ms或者一個閘道器,TTL的值自動減1,當生存時間為0時,報文將被認為目的主機不可到達而丟棄。使用過Ping命令的使用者應該有印象,在windows中輸入ping命令,在返回的結果中即有TTL的數值。 
協議:該欄位指出在上層(網路7層結構或TCP/IP的傳輸層)使用的協議,可能的協議有UDP、TCP、ICMP、IGMP、IGP等。 
首部校驗和:用於檢驗IP報文頭部在傳播的過程中是否出錯,主要校驗報文頭中是否有某一個或幾個bit被汙染或修改了。 
源IP地址:32位(bit),4個位元組,每一個位元組為0~255之間的整數,及我們日常見到的IP地址格式。 
目的IP地址:32位(bit),4個位元組,每一個位元組為0~255之間的整數,及我們日常見到的IP地址格式。

當然對ip理解的越深刻越好了,那麼這樣就完成了一個簡單的match擴充套件的例子,僅僅作為拋磚引玉,一個小小的開始.

相關推薦

iptables深入解析-filter應用

     上一篇文章分析了iptables程式碼下發運作的流程細節,篇幅有限還有很多需要補充.關於netfilter的框架網上已經被講爛了,框架很簡單,但是實現卻不簡單.但不論什麼都要最終歸到實際應用上,才能體現其價值.      下面我們就以iptables1.4.21  ubuntu14 32位  核心版

iptables深入解析:mangle

http://blog.jobbole.com/90008/ 講了filter、ct、nat 現在剩下最後一個知名模組mangle,但是自身雖然知道核心支援修改資料包的資訊,它主要用在策略路由和qos上.我們就具體分析一下. mangle表主要用於

從零開始學習 ASP.NET MVC 1.0 (五) ViewEngine 深入解析應用例項

《從零開始學習ASP.NET MVC 1.0》 文章導航 一.摘要 本文講解ViewEngine的作用, 並且深入解析了實現ViewEngine相關的所有介面和類, 最後演示瞭如何開發一個自定義的ViewEngine. 本系列文章已經全部更新為ASP.NET MVC 1.0版本.希望大家多多支援!

從零開始學習 ASP.NET MVC 1.0 (三) Controller/Action 深入解析應用例項

《從零開始學習ASP.NET MVC 1.0》 文章導航 一.摘要 一個Url請求經過了Routing處理後會呼叫Controller的Action方法. 中間的過程是怎樣的? Action方法中返回ActionResult物件後,如何到達View的? 本文將講解Controller的基本用法, 

(轉)從零開始學習ASP.NET MVC(三) Controller/Action 深入解析應用

一.摘要 一個Url請求經過了Routing處理後會呼叫Controller的Action方法. 中間的過程是怎樣的? Action方法中返回ActionResult物件後,如何到達View的? 本文將講解Controller的基本用法,  深入分析Controller的執行機制, 並且提供了建立所有型別A

深入解析java應用程式的一般架構(好文)

當我們架設一個系統的時候通常需要考慮到如何與其他系統互動,所以我們首先需要知道各種系統之間是如何互動的,使用何種技術實現。1. 不同系統不同語言之間的互動現在我們常見的不同系統不同語言之間的互動使用WebService,Http請求。WebService,即“Web 服務”,

oracle12C資料庫JSON的應用 --PL/SQL儲存過程中JSON解析應用

最近有些專案在資料庫oracle中使用到json格式的資料互動,對於oracle12以上的版本都支援JSON格式資料的使用,剛剛接觸的猿們可以到上一篇oracle資料庫使用json的簡單入門,最好參考官方的API文件關於oracle官方API文件對JSON的支援; 下面就比較詳細的說一下,關

貼上JNA—JNI終結者、深入解析JNA—模擬C語言結構體兩文章的完整原始碼

原文 http://blog.csdn.net/shendl/archive/2008/12/26/3599854.aspx 貼上 JNA—JNI 終結者 、 深入解析 JNA— 模擬 C 語言結構體 兩篇文章的完整原始碼 C 語言

BlockingQueue深入解析-BlockingQueue看這一就夠了

BlockingQueue深入解析-BlockingQueue看這一篇就夠了 轉載:https://www.cnblogs.com/WangHaiMing/p/8798709.html 本篇將詳細介紹BlockingQueue,以下是涉及的主要內容: BlockingQueue

這是一對Python深入解析的文章,附帶入門技巧,不看你就虧了!

這是一篇對Python深入解析的文章,附帶入門技巧,不看你就虧了! 隨著機器學習的興起,Python 逐步成為了「最受歡迎」的語言。它簡單易用、邏輯明確並擁有海量的擴充套件包,因此其不僅成為機器學習與資料科學的首選語言,同時在網頁、資料爬取可科學研究等方面成為不二選擇。此外,很多入

Kubernetes應用部署模型解析(原理

十多年來Google一直在生產環境中使用容器執行業務,負責管理其容器叢集的系統就是Kubernetes的前身Borg。其實現在很多工作在Kubernetes專案上的Google開發者先前就在Borg這個專案上工作。多數Kubernetes的應用部署模型的思想都起源於Bor

貼上 JNA—JNI 終結者 、 深入解析 JNA— 模擬 C 語言結構體 兩文章的完整原始碼 (續)...

原文 http://blog.csdn.net/shendl/archive/2008/12/26/3599854.aspx /** * @param args */ public static void main(String[] args

深入解析開源專案之Universal-Image-Loader(二)快取

Universal-Image-Loader 是一個優秀的圖片載入開源專案,Github地址在 (Github地址) ,很多童鞋都在自己的專案中用到了。優秀的專案從來都是把簡單留給開發者,把複雜封裝在框架內部。ImageLoader作為Github上S

某網Vue.js 原始碼全方位深入解析(實戰)

第1章 準備工作介紹了 Flow、Vue.js 的原始碼目錄設計、Vue.js 的原始碼構建方式,以及從入口開始分析了 Vue.js 的初始化過程。1-1 課程簡介1-2 準備工作1-3 認識 Flow-文件1-4 認識 Flow1-5 Vue.js 原始碼目錄設計-文件

深入解析病毒(一)理論

amp obj ice 不可 表現 當前 text 系統調用 空白 豬年送安康,祝大家新一年健康、快樂。願大家都做一個勤奮努力、真誠奉獻的人,幸運會永遠的眷顧你們。?引子:?某一天饒有興趣在卡飯上瀏覽著帖子,故事的相遇就那麽簡單。當時一條評論勾起我的好奇心,那麽好逆向開始。

基礎深入解析JAVA註解機制

[TOC](目錄標題) # java實現註解的底層原理和概念 - java註解是JDK1.5引入的一種註釋機制,java語言的類、方法、變數、引數和包都可以被註解標註。和Javadoc不同,java註解可以通過反射獲取標註內容 - 在編譯器生成.class檔案時,註解可以被嵌入位元組碼中,而jvm也可以保

MySQL主從復制原理深入解析與練習

數據庫 記錄 sql語句 change master MySQL主從復制原理深入解析與練習MySQL主從復制畫圖描述:MySQL主從復制原理上圖詳解:① 用戶做crud操作,寫入數據庫,更新結果記錄到binlog中;② 主從同步是主找從的,從庫IO發起請求,主庫的主進程看從庫的master

深入解析瀏覽器的幕後工作原理(三) 呈現樹和 DOM 樹的關系

文本 一行 出現 src 格式 關於 放置 顯示 關系 呈現樹和 DOM 樹的關系   呈現器是和 DOM 元素相對應的,但並非一一對應。非可視化的 DOM 元素不會插入呈現樹中,例如“head”元素。如果元素的 display 屬性值為“none”,那麽也不會顯示在呈現

深入解析瀏覽器的幕後工作原理(二) 呈現引擎

div 分享 image ima 好的 clas logs 指令 開放源代碼 呈現引擎   本文所討論的瀏覽器(Firefox、Chrome 瀏覽器和 Safari)是基於兩種呈現引擎構建的。Firefox 使用的是 Gecko,這是 Mozilla 公司“自制”的呈現

jQuery技術內幕:深入解析jQuery架構設計與實現原理

源碼 att root 功能 技術內幕 瀏覽器 sel 緩存 callbacks jQuery源碼(jquery-1.7.1.js)的總體結構:(function( window, undefined ) {// 構造jQuery對象 var jQuery = (fun