動態協議跟蹤機制
例如ftp這種動態協議會通過一個控制串連來建立另一個關聯串連,而linux作業系統的本身實現上,並沒有非常靈活的實現這一點。代碼如下所示:
- static struct ip_conntrack_helper ftp[MAX_PORTS];
- static int __init init(void)
- {
- int i, ret;
- char *tmpname;
- if (ports[0] == 0)
- ports[0] = FTP_PORT;
- //MAX_PORTS為8,也就是當載入模組時,必須要指定源端連接埠
- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
- ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
- ftp[i].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i].mask.src.u.tcp.port = 0xFFFF;
- ftp[i].mask.dst.protonum = 0xFFFF;
- ftp[i].max_expected = 1;
- ftp[i].timeout = 0;
- ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
- ftp[i].me = ip_conntrack_ftp;
- ftp[i].help = help;
- tmpname = &ftp_names[i][0];
- if (ports[i] == FTP_PORT)
- sprintf(tmpname, "ftp");
- else
- sprintf(tmpname, "ftp-%d", ports[i]);
- ftp[i].name = tmpname;
- DEBUGP("ip_ct_ftp: registering helper for port %d/n",
- ports[i]);
- //註冊ip_conntrack_helper
- ret = ip_conntrack_helper_register(&ftp[i]);
- if (ret) {
- fini();
- return ret;
- }
- ports_c++;
- }
- return 0;
- }
這種情況下,當FTP使用大量的非標準連接埠,主串連則無法正常記錄對應的相關串連。因此這裡有一個變通的做法,讓所有的ftp主串連都找不到相關串連,將一個helper_binding函數註冊到應用識別(一個根據資料包內容來判斷串連種類的模組)上,當應用識別識別出當前的串連為ftp串連時,則調用helper_binding通過名字尋找再將ftp的這個ip_conntrack_helper和這個主串連關聯起來。
我們設定ftp[i].mask.src.u.tcp.port = 0x0000;,因為這個賦值會導致所有的串連都不符合要求,因此應該沒有什麼應用和這個相衝突。在init_conntrack函數中會為每個主串連尋找對應的helper,代碼如下:
/* Look up the conntrack helper for master connections only */
if (!expected)
conntrack->helper = ip_ct_find_helper(&repl_tuple);
最終這個函數會調用到helper_cmp,所以我們可以修改這函數,令其直接返回。
- static inline int
- helper_cmp(const struct ip_nat_helper *helper,
- const struct ip_conntrack_tuple *tuple)
- {
- //添加的判斷代碼
- if (helper->mask.src.u.tcp.port == 0 &
- (helper->tuple.dst.protonum == IPPROTO_TCP || helper->tuple.dst.protonum == IPPROTO_UDP))
- return 0;
- else
- return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
- }
在串連被應用識別識別為ftp後,在相應的後麵包的Ip_conntrack_in函數中都會相應的調用help函數,代碼如下所示:
- /* Netfilter hook itself. */
- unsigned int ip_conntrack_in(unsigned int hooknum,
- struct sk_buff **pskb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
- {
- struct ip_conntrack *ct;
- enum ip_conntrack_info ctinfo;
- struct ip_conntrack_protocol *proto;
- int set_reply;
- int ret;
- //…
- //…
- if (ret != NF_DROP && ct->helper) {
- //調用help函數
- ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,
- ct, ctinfo);
- if (ret == -1) {
- /* Invalid */
- nf_conntrack_put((*pskb)->nfct);
- (*pskb)->nfct = NULL;
- return NF_ACCEPT;
- }
- }
- if (set_reply)
- set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
- return ret;
- }