日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

netfilter中IP協(xié)議跟蹤和NAT實(shí)現(xiàn)

 womking 2007-08-16
netfilter中IP協(xié)議跟蹤和NAT實(shí)現(xiàn)

本文檔的Copyleft歸yfydz所有,使用GPL發(fā)布,可以自由拷貝,轉(zhuǎn)載,轉(zhuǎn)載時請保持文檔的完整性,嚴(yán)禁用于任何商業(yè)用途。
msn: [email]yfydz_no1@hotmail.com[/email]
來源:[url]http://yfydz.[/url]

1. 前言

和匹配和目標(biāo)一樣,netfilter提供了模塊化的IP層協(xié)議的跟蹤和NAT處理,除了內(nèi)核自帶的模塊外,用戶可以根據(jù)模塊格式自己編寫其他IP協(xié)議的跟蹤和NAT處理。注意:本文針對的跟蹤和NAT模塊是針對IP上層的協(xié)議,如TCP、UDP、ICMP等,而TCP、UDP上層的協(xié)議如FTP、TFTP等的跟蹤和NAT使用其他方式處理,將在以后的文章中介紹。

2. tuple

在具體介紹IP協(xié)議跟蹤前,需要說明一個結(jié)構(gòu)ip_conntrack_tuple,這是netfilter用來描述跟蹤或NAT各IP協(xié)議時需要跟蹤或修改的各協(xié)議的信息,這些信息和連接的一一對應(yīng)的,對于所有IP協(xié)議,協(xié)議類型、源地址、目的地址這三個參數(shù)是識別連接所必須的,具體到各個協(xié)議,就要提取出各協(xié)議的唯一特征數(shù)據(jù),如TCP、UDP的源端口、目的端口,ICMP的ID、TYPE、CODE等值,這些值就是tuple結(jié)構(gòu)要處理的數(shù)據(jù)。各協(xié)議相關(guān)數(shù)據(jù)是以聯(lián)合形式定義在tuple結(jié)構(gòu)中的,netfilter缺省支持TCP、UDP和ICMP協(xié)議,如果還要支持其他IP協(xié)議,如GRE、ESP、AH、SCTP等,需要在聯(lián)合中添加相應(yīng)的協(xié)議參數(shù)值。

include/linux/netfilter_ipv4/ip_conntrack_tuple.h
/* The protocol-specific manipulable parts of the tuple: always in
   network order! */
union ip_conntrack_manip_proto
{
/* Add other protocols here. */
u_int16_t all;
struct {
  u_int16_t port;
} tcp;
struct {
  u_int16_t port;
} udp;
struct {
  u_int16_t id;
} icmp;
};
/* The manipulable part of the tuple. */
struct ip_conntrack_manip
{
u_int32_t ip;
union ip_conntrack_manip_proto u;
};

/* This contains the information to distinguish a connection. */
struct ip_conntrack_tuple
{
struct ip_conntrack_manip src;
/* These are the parts of the tuple which are fixed. */
struct {
  u_int32_t ip;
  union {
   /* Add other protocols here. */
   u_int16_t all;
   struct {
    u_int16_t port;
   } tcp;
   struct {
    u_int16_t port;
   } udp;
   struct {
    u_int8_t type, code;
   } icmp;
  } u;
  /* The protocol. */
  u_int16_t protonum;
} dst;
};

3. 協(xié)議連接跟蹤

netfilter中對每個要進(jìn)行跟蹤的IP協(xié)議定義了以下結(jié)構(gòu),每個IP協(xié)議的連接跟蹤處理就是要填寫這樣一個結(jié)構(gòu):

include/linux/netfilter_ipv4/ip_conntrack_protocol.h
struct ip_conntrack_protocol
{
/* Next pointer. */
struct list_head list;
/* Protocol number. */
u_int8_t proto;
/* Protocol name */
const char *name;
/* Try to fill in the third arg; return true if possible. */
int (*pkt_to_tuple)(const void *datah, size_t datalen,
       struct ip_conntrack_tuple *tuple);
/* Invert the per-proto part of the tuple: ie. turn xmit into reply.
  * Some packets can‘t be inverted: return 0 in that case.
  */
int (*invert_tuple)(struct ip_conntrack_tuple *inverse,
       const struct ip_conntrack_tuple *orig);
/* Print out the per-protocol part of the tuple. */
unsigned int (*print_tuple)(char *buffer,
        const struct ip_conntrack_tuple *);
/* Print out the private part of the conntrack. */
unsigned int (*print_conntrack)(char *buffer,
     const struct ip_conntrack *);
/* Returns verdict for packet, or -1 for invalid. */
int (*packet)(struct ip_conntrack *conntrack,
        struct iphdr *iph, size_t len,
        enum ip_conntrack_info ctinfo);
/* Called when a new connection for this protocol found;
  * returns TRUE if it‘s OK.  If so, packet() called next. */
int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,
     size_t len);
/* Called when a conntrack entry is destroyed */
void (*destroy)(struct ip_conntrack *conntrack);
/* Has to decide if a expectation matches one packet or not */
int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
          struct sk_buff **pskb);
/* Module (if any) which this is connected to. */
struct module *me;
};

結(jié)構(gòu)中包括以下參數(shù):

struct list_head list:這是將該結(jié)構(gòu)掛接到協(xié)議跟蹤鏈表中的
u_int8_t proto:協(xié)議號,在IP頭中的協(xié)議號是8位,1為ICMP,2為IGMP,6為TCP,17為UDP等等
const char *name:協(xié)議名稱,字符串常量
struct module *me:指向模塊本身,統(tǒng)計(jì)模塊是否被使用

結(jié)構(gòu)中包括以下函數(shù):

(*pkt_to_tuple):將數(shù)據(jù)包中的信息提取到tuple結(jié)構(gòu)中,如對于TCP/UDP,提取其端口值,在net/ipv4/netfilter/ip_conntrack_core.c的get_tuple()函數(shù)中調(diào)用;

(*invert_tuple):將tuple中數(shù)據(jù)進(jìn)行倒置,用來匹配處理連接的返回包,如對于TCP/UDP,要將端口值倒置,在net/ipv4/netfilter/ip_conntrack_core.c的invert_tuple()函數(shù)中調(diào)用;

(*print_tuple):打印協(xié)議相關(guān)的tuple值,在查看/proc/net/ip_conntrack文件時調(diào)用,net/ipv4/netfilter/ip_conntrack_standalone.c;

(*print_conntrack):打印協(xié)議相關(guān)的值,在查看/proc/net/ip_conntrack文件時調(diào)用,net/ipv4/netfilter/ip_conntrack_standalone.c;

(*packet):判斷數(shù)據(jù)包是否合法,并調(diào)整相應(yīng)連接的信息,也就是實(shí)現(xiàn)各協(xié)議的狀態(tài)檢測,對于UDP等本身是無連接的協(xié)議的判斷比較簡單,netfilter建立一個虛擬連接,每個新發(fā)包都是合法包,只等待回應(yīng)包到后連接都結(jié)束;但對于TCP之類的有狀態(tài)協(xié)議必須檢查數(shù)據(jù)是否符合協(xié)議的狀態(tài)轉(zhuǎn)換過程,這是靠一個狀態(tài)轉(zhuǎn)換數(shù)組實(shí)現(xiàn)的,在我以前的文章“什么是狀態(tài)檢測”中對這個數(shù)組進(jìn)行了描述。在net/ipv4/netfilter/ip_conntrack_core.c的ip_conntrack_in()函數(shù)中調(diào)用;

(*new):判斷是否是該協(xié)議的新連接,如對于TCP,必須用SYN包表示連接開始,而對于UDP和ICMP則始終是新連接,在net/ipv4/netfilter/ip_conntrack_core.c的init_conntrack()函數(shù)中調(diào)用;

(*destroy):在系統(tǒng)刪除連接時釋放該協(xié)議的特定數(shù)據(jù),不過目前都沒有使用,在net/ipv4/netfilter/ip_conntrack_core.c的destroy_conntrack()函數(shù)中調(diào)用;

(*exp_matches_pkt):判斷該數(shù)據(jù)包是否是期待的新包還是以前的重發(fā)包,只是在NAT處理時使用,針對的是有序列號控制的協(xié)議,如TCP,而無序列號控制的協(xié)議無此函數(shù)處理,在net/ipv4/netfilter/ip_nat_core.c的exp_for_packet()函數(shù)中調(diào)用;
最后,這些協(xié)議跟蹤結(jié)構(gòu)在net/ipv4/netfilter/ip_conntrack_core.c的

ip_conntrack_init()函數(shù)中掛接到協(xié)議跟蹤鏈表中:
list_append(&protocol_list, &ip_conntrack_protocol_tcp);
list_append(&protocol_list, &ip_conntrack_protocol_udp);
list_append(&protocol_list, &ip_conntrack_protocol_icmp);

要編寫自己的IP協(xié)議跟蹤模塊,先要分析這些協(xié)議頭中哪些信息可以用來唯一識別連接,作NAT時要修改哪些信息,把這些信息添加到ip_conntrack_tuple結(jié)構(gòu)的聯(lián)合中;然后填寫該協(xié)議的ip_conntrack_protocol結(jié)構(gòu),實(shí)現(xiàn)結(jié)構(gòu)中的內(nèi)部函數(shù);最后在ip_conntrack_init()函數(shù)中將此結(jié)構(gòu)掛接到協(xié)議跟蹤鏈表中。

4. 協(xié)議NAT

netfilter中對每個要進(jìn)行NAT的IP協(xié)議定義了以下結(jié)構(gòu),每個IP協(xié)議的NAT處理就是要填寫這樣一個結(jié)構(gòu):

include/linux/netfilter_ipv4/ip_nat_protocol.h
struct ip_nat_protocol
{
struct list_head list;
/* Protocol name */
const char *name;
/* Protocol number. */
unsigned int protonum;
/* Do a packet translation according to the ip_nat_proto_manip
  * and manip type. */
void (*manip_pkt)(struct iphdr *iph, size_t len,
     const struct ip_conntrack_manip *manip,
     enum ip_nat_manip_type maniptype);
/* Is the manipable part of the tuple between min and max incl? */
int (*in_range)(const struct ip_conntrack_tuple *tuple,
   enum ip_nat_manip_type maniptype,
   const union ip_conntrack_manip_proto *min,
   const union ip_conntrack_manip_proto *max);
/* Alter the per-proto part of the tuple (depending on
    maniptype), to give a unique tuple in the given range if
    possible; return false if not.  Per-protocol part of tuple
    is initialized to the incoming packet. */
int (*unique_tuple)(struct ip_conntrack_tuple *tuple,
       const struct ip_nat_range *range,
       enum ip_nat_manip_type maniptype,
       const struct ip_conntrack *conntrack);
unsigned int (*print)(char *buffer,
         const struct ip_conntrack_tuple *match,
         const struct ip_conntrack_tuple *mask);
unsigned int (*print_range)(char *buffer,
        const struct ip_nat_range *range);
};

結(jié)構(gòu)中包括以下參數(shù):

struct list_head list:這是將該結(jié)構(gòu)掛接到協(xié)議跟蹤鏈表中的
const char *name:協(xié)議名稱,字符串常量
unsigned int protonum:協(xié)議號,在IP頭中的協(xié)議號是8位,在此用unsigned int有點(diǎn)浪費(fèi)

結(jié)構(gòu)中包括以下函數(shù):

(*manip_pkt):修改協(xié)議相關(guān)數(shù)據(jù),根據(jù)NAT規(guī)則來確定是修改源部分還是目的部分,在net/ipv4/netfilter/ip_nat_core.c的manip_pkt()函數(shù)中調(diào)用;

(*in_range):判斷數(shù)據(jù)包是否是要進(jìn)行NAT修改,在net/ipv4/netfilter/ip_nat_core.c的in_range()、get_unique_tuple()等函數(shù)中調(diào)用;

(*unique_tuple):構(gòu)造一個新tuple處理將原tuple在進(jìn)行NAT后對應(yīng)的連接參數(shù),如TCP源NAT時,除了源地址必須要修改外,一般還要修改源端口,這個連接的后續(xù)包的源端口就都改這個端口值,而修改后的這個端口值必須是唯一的,和這個連接綁定,其他連接就不能再使用這個端口,如果找不到合適的tuple值,NAT將失敗,也就是說,對于多對一的NAT轉(zhuǎn)換,理論上最多只能處理65535個TCP連接,超過此數(shù)的新的TCP連接就無法進(jìn)行NAT了,對于TCP、UDP,(*unique_tuple)就是檢測查找一個新的未用端口生成一個新的tuple結(jié)構(gòu)對應(yīng)該連接,對應(yīng)ICMP,則是找一個未用的ID值,該函數(shù)在net/ipv4/netfilter/ip_nat_core.c的get_unique_tuple()函數(shù)中調(diào)用;

(*print):打印struct ip_conntrack_tuple中的協(xié)議相關(guān)信息;

(*print_range):打印struct ip_nat_range結(jié)構(gòu)中要進(jìn)行NAT修改的那部分協(xié)議信息;

最后,這些協(xié)議跟蹤結(jié)構(gòu)在net/ipv4/netfilter/ip_nat_core.c的ip_nat_init()函數(shù)中掛接到協(xié)議NAT鏈表中:
list_append(&protos, &ip_nat_protocol_tcp);
list_append(&protos, &ip_nat_protocol_udp);
list_append(&protos, &ip_nat_protocol_icmp);
對新IP協(xié)議的NAT模塊的添加和跟蹤模塊的添加類似。

5. 其他IP協(xié)議的跟蹤和NAT

下面討論其他IP協(xié)議如果要進(jìn)行跟蹤和NAT要處理哪些協(xié)議相關(guān)數(shù)據(jù):

SCTP:RFC2960,協(xié)議號132,和TCP非常類似,用源端口和目的端口來識別;
                 SCTP Common Header Format
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Source Port Number        |     Destination Port Number   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Verification Tag                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Checksum                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

IGMP:RFC3376,協(xié)議號2,IGMP頭內(nèi)信息太少,沒有特殊數(shù)據(jù)供識別
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      Type     | Max Resp Time |           Checksum            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         Group Address                         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

GRE:RFC1701,RFC2784,協(xié)議號47,使用KEY來作為修改數(shù)據(jù),ver和protocol作為識別用的固定數(shù)據(jù)

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|C|R|K|S|s|Recur|  Flags  | Ver |         Protocol Type         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Checksum (optional)      |       Offset (optional)       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Key (optional)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Sequence Number (optional)                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Routing (optional)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|C|       Reserved0       | Ver |         Protocol Type         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Checksum (optional)      |       Reserved1 (Optional)    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

ESP:RFC4303,協(xié)議號50,只能用SPI來識別,SPI是SA的一部分,不過是不能修改的,因?yàn)镾PI是在IKE協(xié)商過程中確定的,兩邊都已經(jīng)預(yù)先知道,一旦修改了就匹配不到SA了

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               Security Parameters Index (SPI)                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |                      Sequence Number                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Payload Data* (variable)                   |
|                                                               |
|                                                               |
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|               |     Padding (0-255 bytes)                     |
+-+-+-+-+-+-+-+-+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               |  Pad Length   | Next Header   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Integrity Check Value-ICV   (variable)                |
~                                                               ~
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

AH:RFC4304,協(xié)議號51,AH協(xié)議無法進(jìn)行NAT的,否則認(rèn)證就會失敗,跟蹤也只能靠SPI

6. 結(jié)論

netfilter的IP協(xié)議跟蹤和NAT處理很好地實(shí)現(xiàn)了模塊化,但除了netfilter自帶的模塊外,可處理其他IP協(xié)議也已經(jīng)不多了,只有GRE和SCTP可以新增模塊,其他協(xié)議增加模塊基本無意義。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多