大师的错误?UNP1中raw socket不能接收TCP和UDP的错误
2016-06-28 14:48
387 查看
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
在UNP1中的28.4 Raw Socket Input中,大师是这样说的。
中文版是这样说的。
1. 接收到UDP分组和TCP分组绝不传递到任何原始套接口。如果一个进程想要读取含有UDP分组或TCP分组的IP数据报,它就必须在数据链路层读取这些分组。
首先,要严重鄙视一下中文版的翻译!什么叫UDP分组和TCP分组?!
反正我在看到中文版这个部分的时候,就很疑惑?分组,是分片的笔误还是组播?然后对照了原文,唉,为啥不翻译成报文呢。
看来我以后全看英文版的决定还是无比正确的。
下面回到正题。根据大师的说法,raw socket是无法收到TCP和UDP的数据包的。可是根据我的使用,情况不是这样。在我前面的博文《kernel对于SO_REUSEADDR的处理——避免滥用引发Bug》http://blog.chinaunix.net/space.php?uid=23629988&do=blog&id=217123中,我特意用了raw
socket在不影响绑定同一地址和端口的socket情况下,来获取UDP数据包(clone)。代码工作完全正常。
今天跟同事谈到这个问题,跟他说明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是开源的,还是代码说明了一切!
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
在UNP1中的28.4 Raw Socket Input中,大师是这样说的。
Received UDP packets and received TCP packets are never passed to a raw socket. If a process wants to read IP datagrams containing UDP or TCP packets, the packets must be read at the datalink layer, as described in Chapter 29. |
1. 接收到UDP分组和TCP分组绝不传递到任何原始套接口。如果一个进程想要读取含有UDP分组或TCP分组的IP数据报,它就必须在数据链路层读取这些分组。
首先,要严重鄙视一下中文版的翻译!什么叫UDP分组和TCP分组?!
反正我在看到中文版这个部分的时候,就很疑惑?分组,是分片的笔误还是组播?然后对照了原文,唉,为啥不翻译成报文呢。
看来我以后全看英文版的决定还是无比正确的。
下面回到正题。根据大师的说法,raw socket是无法收到TCP和UDP的数据包的。可是根据我的使用,情况不是这样。在我前面的博文《kernel对于SO_REUSEADDR的处理——避免滥用引发Bug》http://blog.chinaunix.net/space.php?uid=23629988&do=blog&id=217123中,我特意用了raw
socket在不影响绑定同一地址和端口的socket情况下,来获取UDP数据包(clone)。代码工作完全正常。
今天跟同事谈到这个问题,跟他说明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是开源的,还是代码说明了一切!
相关文章推荐
- OkHttp3源码分析[任务队列]
- pip install Error - ReadTimeoutError: HTTPSConnectionPool(host='pypi.python.org', port=443): Read
- iOS 偶说获取网络请求到的图片尺寸
- 用开源工具Xplico助力网络应用层数据解码
- 简单介绍HttpURLConnection请求网络以及AsyncTask异步任务的用法
- @font-face的用法 WebFont网络字体
- Android网络请求框架--AsyncHttpClient
- Http协议
- Curl http_code 状态码 意义及信息
- SSH 远程登录 基础知识
- @font-face 网络字体的中文用法(一)
- java代码模拟http请求
- httpd设置HTTPS双向认证
- 网络协议_计算机网络_本机ip、127.0.0.1和0.0.0.0区别
- VMware 虚拟机下网络配置基础
- Retrofit网络通信库简单封装使用
- HDU 3572 网络流
- 如何绘制caffe网络训练曲线
- 如何绘制caffe网络训练曲线
- 社交网络中信息内容的计算公式