📄 118.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>123</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center"> ● UNIX网络编程 (BM: clown) </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="116.htm">上一层</a>][<a href="119.htm">下一篇</a>]
<hr><p align="left"><small>发信人: ysqcn (岁月无声), 信区: UNP <br>
标 题: 对linux中socket(AF_INET,SOCK_RAW,protocol)的讨论 <br>
发信站: UNIX编程 (2001年07月23日17:25:19 星期一), 站内信件 <br>
<br>
对linux中socket(AF_INET,SOCK_RAW,protocol)中protocol的讨论 <br>
<br>
一.透过源码看问题 <br>
<br>
在创建原始套接字的时候inet_create: <br>
<br>
switch (sock->type) { <br>
>>>>对原始套接字 <br>
case SOCK_RAW: <br>
>>>>是不是有超级用户权限 <br>
if (!capable(CAP_NET_RAW)) <br>
goto free_and_badperm; <br>
>>>>linux下protocol不能为零 <br>
if (!protocol) <br>
goto free_and_noproto; <br>
prot = &raw_prot; <br>
sk->reuse = 1; <br>
>>>>用num记录了这个protocol,后面会用到 <br>
sk->num = protocol; <br>
sock->ops = &inet_dgram_ops; <br>
>>>>如果为IPPROTO_RAW,则可以自己写IP头 <br>
if (protocol == IPPROTO_RAW) <br>
sk->protinfo.af_inet.hdrincl = 1; <br>
break; <br>
default: <br>
goto free_and_badtype; <br>
} <br>
<br>
。。。。。。。。。 <br>
<br>
>>>>原始套接字前面num被赋值为protocol <br>
if (sk->num) { <br>
sk->sport = htons(sk->num); <br>
/* Add to protocol hash chains. */ <br>
>>>>实际的函数是raw_v4_hash,创建的时候就将它链接到raw_v4_htable中, <br>
>>>>注意了,hash值的计算:哈希值=sk->num & 31 <br>
>>>>如果为IPPROTO_RAW=255,就链接到raw_v4_htable[31]中了 <br>
sk->prot->hash(sk); <br>
} <br>
<br>
raw的bind和connetc与udp的一样,设置一下本地地址与对方地址,raw没有端口的概念。 <br>
<br>
数据报投递上来的时候ip_local_deliver_finish(struct sk_buff *skb): <br>
<br>
>>>>根据IP报文中的协议字段计算hash字,会不会出现这个协议字段是IPPROTO_RAW, <br>
>>>>即255的情况,我想除了自己发包外,TCP,UDP,ICMP,IGMP应该不会出现吧:( <br>
int hash = protocol & (MAX_INET_PROTOS - 1); <br>
>>>>根据这个hash字到相应的raw_v4_htable中去找匹配的接受套接字 <br>
struct sock *raw_sk = raw_v4_htable[hash]; <br>
>>>>如果有原始接受套接字,则调用raw_v4_input进行处理 <br>
if(raw_sk != NULL) <br>
raw_sk = raw_v4_input(skb, skb->nh.iph, hash); <br>
<br>
<br>
下面就是raw_v4_input的简略过程了: <br>
<br>
struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) <br>
{ <br>
struct sock *sk; <br>
<br>
read_lock(&raw_v4_lock); <br>
>>>>还是根据这个hash值到对应的raw_v4_htable中查找了 <br>
if ((sk = raw_v4_htable[hash]) == NULL) <br>
goto out; <br>
sk = __raw_v4_lookup(sk, iph->protocol, <br>
iph->saddr, iph->daddr, <br>
skb->dev->ifindex); <br>
while(sk != NULL) { <br>
>>>>依次根据sk组成的链表来编历协议、地址匹配的原始套接字 <br>
struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol, <br>
iph->saddr, iph->daddr, <br>
skb->dev->ifindex); <br>
。。。。。。。。 <br>
sk = sknext; <br>
............... <br>
} <br>
........... <br>
} <br>
<br>
二、结论 <br>
<br>
根据上面代码,至少可以得到如下的结论(适用于linux下): <br>
<br>
1.protocol决不能为零,否则创建套接字将失败 <br>
<br>
<br>
2.所以protocol可以为下面的标准的“官方值”: <br>
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ <br>
IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ <br>
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ <br>
IPPROTO_TCP = 6, /* Transmission Control Protocol */ <br>
IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ <br>
IPPROTO_PUP = 12, /* PUP protocol */ <br>
IPPROTO_UDP = 17, /* User Datagram Protocol */ <br>
IPPROTO_IDP = 22, /* XNS IDP protocol */ <br>
IPPROTO_RSVP = 46, /* RSVP protocol */ <br>
IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */ <br>
IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ <br>
IPPROTO_PIM = 103, /* Protocol Independent Multicast */ <br>
IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ <br>
<br>
IPPROTO_AH = 51, /* Authentication Header protocol */ <br>
IPPROTO_COMP = 108, /* Compression Header protocol */ <br>
以及 <br>
IPPROTO_RAW = 255, /* Raw IP packets */ <br>
其中对IPPROTO_RAW来说,应该与其它区别开来 <br>
IPPROTO_IP是不行的,它的值本身就为0 <br>
<br>
3.如果protocol为上面的除IPPROT_RAW外的其它值,则IP包会传递到相应协议匹配的原 <br>
始套接字,例如如果将protocol设为IPPROTO_TCP,就可以利用原始套接字接受TCP数据 <br>
报,而不会接受到其他协议类型的数据报。 <br>
<br>
4.最可怜的是protocol为IPPROTO_RAW的原始套接字,辛苦一场,结果标准的官方的数据 <br>
报一个也接受不到,除非发送方构造了一个协议字段255的IP报文。 <br>
<br>
5.你可以自定义除那些标准的官方协议字段外的其它值,然后通信的双方都采用这个协 <br>
议字段,这样就可以互相收发数据了。 <br>
<br>
6.强调一下,linux下不能用原始套接字截获所有的IP报文。 <br>
<br>
三、测试证明 <br>
<br>
测试程序太烂了,这里就不给出了。测试程序验证了上面1-5的结论是正确的:) <br>
<br>
-- <br>
一万年太久,只争朝夕... <br>
※ 修改:·ysqcn 於 07月24日09:00:24 修改本文·[FROM: 202.114.2.11] <br>
※ 来源:·UNIX编程 www.tiaozhan.com/unixbbs/·[FROM: 202.114.2.11] <br>
</small><hr>
<p align="center">[<a href="index.htm">回到开始</a>][<a href="116.htm">上一层</a>][<a href="119.htm">下一篇</a>]
<p align="center"><a href="http://cterm.163.net">欢迎访问Cterm主页</a></p>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -