iptables/netfilter命令、實現及利用(轉)

原文連接:http://blog.csdn.net/sealyao/article/details/5934268linux

1、Netfilter和Iptables概述shell

       netfilter/iptables IP 信息包過濾系統是一種功能強大的工具,可用於添加、編輯和除去規則,這些規則是在作信息包過濾決定時,防火牆所遵循和組成的規則。這些規則存儲在專用的信息包過濾表中,而這些表集成在 Linux 內核中。在信息包過濾表中,規則被分組放在咱們所謂的鏈(chain)中。數組

      雖然 netfilter/iptables IP 信息包過濾系統被稱爲單個實體,但它實際上由兩個組件 netfilteriptables 組成。數據結構

      netfilter 組件也稱爲內核空間(kernelspace),是內核的一部分,由一些信息包過濾表組成,這些表包含內核用來控制信息包過濾處理的規則集。app

      iptables 組件是一種工具,也稱爲用戶空間(userspace),它使插入、修改和除去信息包過濾表中的規則變得容易。socket

      iptables包含4個表,5個鏈。其中表是按照對數據包的操做區分的,鏈是按照不一樣的Hook點來區分的,表和鏈其實是netfilter的兩個維度。tcp

      4個表:filter,nat,mangle,raw,默認表是filter(沒有指定表的時候就是filter表)。表的處理優先級:raw>mangle>nat>filter。函數

          filter:通常的過濾功能工具

          nat:用於nat功能(端口映射,地址映射等)性能

           mangle:用於對特定數據包的修改

           raw:有限級最高,設置raw時通常是爲了避免再讓iptables作數據包的連接跟蹤處理,提升性能

      5個鏈:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING。

           PREROUTING:數據包進入路由表以前

           INPUT:經過路由表後目的地爲本機

           FORWARDING:經過路由表後,目的地不爲本機

           OUTPUT:由本機產生,向外轉發

           POSTROUTIONG:發送到網卡接口以前。以下圖:

image001

    iptables中表和鏈的對應關係以下:

繪圖1.vsd     數據包在netfilter中的傳遞流程:

image005

2、Iptables的使用

iptables [-t 表名] -命令 –鏈表 [-匹配] [-j 動做/目標]

表名:filter;nat;mangle;raw

經常使用命令:

-A, --append chain rule-specification:添加

-D, --delete chain rule-specification:刪除

-D, --delete chain rulenum:刪除

-I, --insert chain [rulenum] rule-specification:插入

-R, --replace chain rulenum rule-specification:替換

-L, --list [chain]:顯示

-F, --flush [chain]:刷新

鏈表:INPUT;OUTPUT;FORWORD;PREROUTING;POSTROUTING

匹配:

-p -protocal [!]protocol:協議

-s -source [!] address[/mask]:源地址

-d --destination [!] address[/mask]:目的地址

-j --jump target:

-i –in-interface [!][name]:入口

-o --out-interface [!][name]:出口

-f, --fragment:分片

匹配擴展:

指定-p tcp時:

--source-port [!] [port[:port]]:原端口(也做--sport)

--destionation-port [!] [port:[port]]:目的端口(也做--dport)

--tcp-flags [!] mask comp:匹配指定的TCP標記

[!] –syn:設置了SYN位而清除了ACK和FIN位的TCP包。

--tcp-option [!] number:設置了TCP選項的包

指定 –p udp時:

--source-port [!] [port:[port]]

--destination-port [!] [port:[port]]

常見動做:

ACCEPT:放行

DROP:拒絕

QUEUE:傳遞給應用層

REJECT:和DROP相似,只是REJECT還返回一個錯誤包消息

REDIRECT:在nat表PREROUTING鏈中使用,修改數據包爲本機地址和用戶指定的端口。

TPROXY:在mangle表的PREROUTING鏈中使用,不修改數據包包頭,直接把數據傳遞給一個本地socket。

較完整的命令參數見下圖:

image007

3、NetFilter的內核實現

Netfilter中有兩個要點:一個是Hooks點的實現,一個是表、鏈、規則的概念

Hooks

struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]是其中核心的數據結構。nf_hooks的功能相似一個二維的函數指針數組。

nf_hooks數組的第一維是按照協議進行分類的,對於不一樣的協議有不一樣的hook點和hook函數,常見的協議包括ipv4,ipv6,arp,bridge等。

nf_hooks數組的第二維是按照hook點進行劃分的,分爲

NF_INET_PRE_ROUTING,NF_INET_LOCAL_IN,NF_INET_FORWARD,NF_INET_LOCAL_OUT,NF_INET_POST_ROUTING等5個hook點,與iptables的5個鏈相對應。

nf_hooks數組中的每個元素能夠理解爲一個函數指針鏈表的鏈表頭。這個函數指針鏈表是一個有序鏈表,按照函數hook的優先級進行排序。iptables的4個表分別對應不一樣的優先級:NF_IP_PRI_RAW、NF_IP_PRI_MANGLE、NF_IP_PRI_NAT_DST /NF_IP_PRI_NAT_SRC、NF_IP_PRI_LAST等。iptables中的表的優先級就是經過有序鏈表的方式來實現的。

鏈表元素的實際的數據結構是struct nf_hook_ops,其核心的數據成員就是一

個函數指針,還包含其餘的一些屬性。

struct nf_hook_ops
{
        struct list_head list;                        //鏈表成員
        /* User fills in from here down. */
        nf_hookfn *hook;                        //鉤子函數指針
        struct module *owner;
        int pf;                             //協議簇,對於ipv4而言,是PF_INET

int hooknum;                                //hook類型
int priority;                                //優先級

};

     nf_hooks的全局結構示意圖以下:

image009     netfilter中的數據流程以下圖:

image011

上圖爲ipv4協議的數據包,當數據包到達對應的hook點時,檢查對應的nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]函數指針鏈表是否爲空,若是爲空則繼續tcp/ip協議棧的後續流程;若是不爲空,則按照鏈表中的順序依次調用hook函數。

iptables的默認的核心hook函數是ipt_do_table(ip_tables.c),其核心功能是檢查對應的協議的對應的表中的對應的鏈中的規則是否和當前的數據包相匹配,若是匹配則執行對應的動做。

Tabales

netfilter中提供了一系列的表(tables),每一個表包含若干個鏈(chains),而每條鏈中包含由一條或若干條規則(rules),每一條規則都被用於數據包的檢測。實際上netfilter是表的容器,表是鏈的容器,而鏈又是規則的容器。

相關的數據結構:

struct xt_table //表結構

{

    struct list_head list;//錶鏈

    unsigned int valid_hooks;

    struct xt_table_info *private;// iptable的數據區

    struct module *me;

    u_int8_t af; //協議簇

    int priority; //優先級

    const char name[XT_TABLE_MAXNAMELEN];// 表名,如"filter"、"nat"等,爲了知足自動模塊加載的設計,包含該表的模塊應命名爲iptable_'name'.o

};

struct ipt_table_info //表的實際數據結構
{

    unsigned int size;//表大小
    unsigned int number;//表中規則數
    unsigned int initial_entries;//初識的規則數,用於模塊計數
    unsigned int hook_entry[NF_IP_NUMHOOKS];// 記錄所影響的HOOK的規則入口相對於下面的entries變量的偏移量
    unsigned int underflow[NF_IP_NUMHOOKS];//與hook_entry相對應的規則表上限偏移量,當無規則錄入時,相應的hook_entry和underflow均爲0
    char entries[0] ____cacheline_aligned;//規則表入口

};

下面的3種數據額結構是被填充到struct ipt_table_info的規則表(entries開始的)中的。

    ipt_entry結構以下圖所示,其成員ip指向結構ipt_ip,該結構主要保存規則中標準匹配的內容 (IP、mask、interface、proto等),target_offset的值等於ipt_entry的長度與 ipt_entry_matches的長度之和,next_offset的值等於規則中三個部分的長度之和。經過target_offset與 next_offset能夠實現規則的遍歷。

struct ipt_entry

{

    struct ipt_ip ip;/* 所要匹配的報文的IP頭信息 */
    unsigned int nfcache;/* 位向量,標示本規則關心報文的什麼部分,暫未使用 */
    u_int16_t target_offset;/* target區的偏移,一般target區位於match區以後,而match區則在ipt_entry的末尾;初始化爲sizeof(struct ipt_entry),即假定沒有match */
    u_int16_t next_offset;/* 下一條規則相對於本規則的偏移,也即本規則所用空間的總和,初始化爲sizeof(struct ipt_entry)+sizeof(struct ipt_target),即沒有match */
    unsigned int comefrom;/* 規則返回點,標記調用本規則的HOOK號,可用於檢查規則的有效性 */
    struct ipt_counters counters;/* 記錄該規則處理過的報文數和報文總字節數 */
    unsigned char elems[0];/*target或者是match的起始位置 */

}

ipt_entry_match主要保存規則中擴展匹配內容(tos、ttl、time等),其是 Netfilter中內核與用戶態交互的關鍵數據結構,在其內核部分由一個函數指針指向一個ipt_match結構,該結構體中包含了對包作匹配的函數, 是真正對包作匹配的地方。ipt_entry_target結構與ipt_entry_match結構很相似。

struct xt_entry_

    union {

        struct {

             __u16 match_size;

            char name[XT_EXTENSION_MAXNAMELEN];

            __u8 revision;

        } user;

        struct {

            __u16 match_size;

           struct xt_match *match;

        } kernel;

        __u16 match_size;

    } u;

    unsigned char data[0];

};

struct xt_entry_target {

    union {

        struct {

             __u16 target_size;

            char name[XT_EXTENSION_MAXNAMELEN];

            __u8 revision;

        } user;

        struct {

            __u16 target_size;

            struct xt_target *target;

        } kernel;

        __u16 target_size;

    } u;

    unsigned char data[0];

};

上面各類數據結構是按照下圖的形式進行關聯的。這裏被分紅表、鏈、規則三級。

每一個表(xt_tables)都有一個private指針指向一個ipt_table_info結構,在ipt_table_info結構以後緊接着的是是實際的規則。

從數據結構中看鏈結構不是很明顯,可是規則是被封裝在鏈中的。ipt_table_info結構中的hook_entry成員和underflow成員就是用於劃分規則所在的鏈。

每一個規則由一個ipt_entry結構,N個xt_entry_match結構和一個xt_entry_target結構組成。ipt_entry結構表示的是基本的匹配規則(協議、地址等),xt_entry_match結構表示的是擴展的匹配規則,xt_entry_target結構表示的是匹配以後的動做。

繪圖1.vsd


4、NetFilter的利用

   因爲netfilter在內核中預留了Hook點,所以能夠經過加載模塊的方式方便對其加以利用。下面代碼能夠在2.6.20上運行。

  1. //nethook.c   
  2. #include <linux/module.h>   
  3. #include <linux/kernel.h>   
  4. #include <linux/netfilter.h>   
  5. #include <linux/netfilter_ipv4.h>   
  6. #include <linux/netdevice.h>   
  7. #include <linux/skbuff.h>   
  8. #include <linux/ip.h>   
  9. #include <linux/tcp.h>   
  10.   
  11. static struct nf_hook_ops nfho;  
  12. unsigned int hook_func(unsigned int hooknum,  
  13.     struct sk_buff **skb,  
  14.     const struct net_device *in,  
  15.     const struct net_device *out,  
  16.     int (*okfn)(struct sk_buff *))  
  17. {  
  18. #ifdef BASE_TEST       
  19.     return NF_DROP;  
  20. #endif   
  21. #ifdef INTF_TEST   
  22.     if(strcmp(in->name,"eth0") == 0){  
  23.         return NF_DROP;  
  24.     }  
  25. #endif   
  26. #ifdef ADDR_TEST   
  27.     static unsigned char *drop_ip = "/x0a/x08/x50/x6c";  
  28.     struct sk_buff *sk = *skb;  
  29.     if(sk->nh.iph->saddr == *(unsigned int *)drop_ip){  
  30.         return NF_DROP;  
  31.     }  
  32. #endif   
  33.   
  34. #ifdef PORT_TEST    
  35.     unsigned char *deny_port = "/x00/x19"/* port 25 */  
  36.     struct tcphdr *thead;  
  37.     if (!skb )  
  38.         return NF_ACCEPT;  
  39.     if (!(skb->nh.iph))  
  40.         return NF_ACCEPT;  
  41.   
  42.     if (skb->nh.iph->protocol != IPPROTO_TCP) {  
  43.         return NF_ACCEPT;  
  44.     }  
  45.     thead = (struct tcphdr *)(skb->data +(skb->nh.iph->ihl * 4));  
  46.   
  47.     if ((thead->dest) == *(unsigned short *)deny_port) {  
  48.         return NF_DROP;  
  49.     }  
  50. #endif   
  51.     return NF_ACCEPT;   
  52. }  
  53.   
  54. static int __init init_nethook(void)  
  55. {  
  56.     nfho.hook = hook_func;   
  57.     nfho.hooknum = NF_IP_PRE_ROUTING;   
  58.     nfho.pf = PF_INET;  
  59.     nfho.priority = NF_IP_PRI_FIRST;   
  60.     nf_register_hook(&nfho);  
  61.     return 0;  
  62. }  
  63.   
  64.   
  65. static void __exit exit_nethook(void)  
  66. {  
  67.     nf_unregister_hook(&nfho);  
  68. }  
  69.   
  70. module_init(init_nethook);  
  71. module_exit(exit_nethook);  

 

 

Makefile:

  1. obj-m = nethook.o  
  2. KVERSION = $(shell uname -r)  
  3. all:  
  4.     make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules   
  5. clean:  
  6.     make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean  

 

 

利用上述模塊能夠簡單實現對地址、端口的過濾

相關文章
相關標籤/搜索