本文的copyleft歸[email protected]所有,使用GPL釋出,可以自由拷貝,轉載。但轉載請保持文檔的完整性,注明原作者及原連結,嚴禁用于任何商業用途。
部落格:linuxfocus.blog.chinaunix.net
在UNP1中的28.4 Raw Socket Input中,大師是這樣說的。
中文版是這樣說的。
1. 接收到UDP分組和TCP分組絕不傳遞到任何原始套接口。如果一個程序想要讀取含有UDP分組或TCP分組的IP資料報,它就必須在資料鍊路層讀取這些分組。
首先,要嚴重鄙視一下中文版的翻譯!什麼叫UDP分組和TCP分組?!
反正我在看到中文版這個部分的時候,就很疑惑?分組,是分片的筆誤還是多點傳播?然後對照了原文,唉,為啥不翻譯成封包呢。
看來我以後全看英文版的決定還是無比正确的。
今天跟同僚談到這個問題,跟他說明linux選擇socket機制時,對于raw socket,隻要該包符合了raw socket的過濾條件,該raw socket就可以獲得一個該包的拷貝。他想讓我找出理論依據,我就找出UNP1來作說明。這才發現UNP1中雖然說了raw socket可以獲得資料包拷貝的事情,但是也說了前提條件。其中UDP和TCP不會交給raw socket是首要條件。這讓我很困惑啊。
如何解決?代碼說明一切。讓我們直接看linux kernel的代碼。
我的kernel代碼是2.6.36.2
static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
unsigned short num, __be32 raddr, __be32 laddr, int dif)
{
struct hlist_node *node;
sk_for_each_from(sk, node) {
struct inet_sock *inet = inet_sk(sk);
if (net_eq(sock_net(sk), net) && inet->inet_num == num &&
!(inet->inet_daddr && inet->inet_daddr != raddr) &&
!(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
!(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
goto found; /* gotcha */
}
sk = NULL;
found:
return sk;
}
static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
struct sock *sk;
struct hlist_head *head;
int delivered = 0;
struct net *net;
read_lock(&raw_v4_hashinfo.lock);
head = &raw_v4_hashinfo.ht[hash];
if (hlist_empty(head))
goto out;
net = dev_net(skb->dev);
sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
while (sk) {
delivered = 1;
if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
/* Not releasing hash */
if (clone)
raw_rcv(sk, clone);
}
sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
iph->saddr, iph->daddr,
skb->dev->ifindex);
out:
read_unlock(&raw_v4_hashinfo.lock);
return delivered;
在__raw_v4_lookup中,隻是去比較位址,端口等過濾條件,則這個raw socket就是比對的。然後在raw_v4_input中,隻要不是ICMP或者不是需要過濾的ICMP type,這個raw socket就可以獲得一個資料包的拷貝。
kernel的代碼無疑已經說明了raw socket完全可以接受TCP或者UDP的資料包。我又檢查了linux2.4的處理,同樣沒有這個限制。
也許大師寫的這個條件不是針對linux的吧——因為對其他unix系統沒有了解,是以不敢枉然說這是大師的錯誤。
不過從這件事可以看出,盡信書不如無書。對于linux程式員,既然kernel是開源的,還是代碼說明了一切!