一年十二月  谁主春秋
关注:基础系统工程 密码学 人工智能
C++博客
首页
新随笔
联系
聚合
管理
随笔-156 评论-223 文章-30 trackbacks-0
Linux ICMP消息的产生与转换
ICMP在IP系统间传递差错和管理报文,是任何IP系统必须实现的组成部分。Linux 2.6.34中ICMP模块的实现在linux/icmp.h,net/icmp.h和ipv4/icmp.c中,导出了
icmp_err_convert
数组和
icmp_send
函数,供其它网络子系统使用。在其它网络子系统中,当检测到错误时,调用icmp_send产生并发送相应的ICMP差错消息到源主机;当源主机收到ICMP不可达差错消息,传递到原始套接字和传输层,而它们使用icmp_err_convert把对应的消息代码转换成套接字层比较容易理解的错误代码。在内核空间中可发送的ICMP消息包括查询应答和差错报文,下面总结了产生这两类消息的网络子系统(及函数)与错误转换。
应答消息
应答消息由ICMP模块的内部函数icmp_reply而非icmp_send发送。根据
RFC1122 3.2.2.9
规范, 除非一个主机作为地址掩码代理,否则不能发送回复,这对应ICMP的icmp_address实现为空,因此上表没有列出地址掩码应答项(内核符号为ICMP_ADDRESSREPLY)。
差错消息
差错消息由中间路由器或目的主机产生,当数据报不能成功提交给目的主机时。从上表可见,在IP层的接收、本地处理、转发和输出各过程中,都可能产生差错消息;在传输层如果对应的端口没有打开,那么UDP会产生ICMP端口不可达差错,而
TCP则会使用自己的差错处理机制发送一个RST复位包,这也是上表没有列出TCP子系统的原因
。对于重定向差错,由ICMP模块的icmp_redirect调用ip_rt_redirect更新路由;其它差错则由icmp_unreach处理。
错误转换
第2列为icmp_err_convert数组索引,第4列也就是调用socket API出错时返回的errno,最后1列为icmp_err_convert中的fatal成员取值,0表示非致命错误,1表示致命错误,需要报告给用户进程。错误转换会被RAW的raw_err、TCP的tcp_v4_err和UDP的udp_err用到,对于ICMP_DEST_UNREACH类型的差错,使用上表转换;ICMP_SOURCE_QUENCH类型的忽略不处理;ICMP_PARAMETERPROB类型的转换成
EPROTO
(协议错误);ICMP_TIME_EXCEEDED类型的转换成
EHOSTUNREACH
。
在这要注意,从ICMP_PORT_UNREACH到ECONNREFUSED的转换,不适用于TCP,原因已在
上节
说明;而对于UDP的
未连接
套接字,如果主机在线而端口没打开,调用sendto得不到ECONNREFUSED错误,但recvfrom会阻塞,这是因为虽然内核收到了ICMP差错,但没上报给应用进程。尽管如此,如果想得到ECONNREFUSED错误,那么可以写个ICMP守护进程,应用进程先把它的套接字描述符通过unix域套接口传递到ICMP守护进程,而守护进程使用raw socket来接收ICMP差错,再发给应用进程。
发送限速
不论一般差错消息还是重定向差错消息,发送限速针对的都是特定目标主机。
一般限速
在使用icmp_send发送差错消息(PMTU消息除外)时,为减少网络拥塞而限制了发送的速率,限速由xrlim_allow函数实现,定义在ipv4/icmp.c中。
1
#define
XRLIM_BURST_FACTOR
6
2
int
xrlim_allow
(
struct
dst_entry
*
dst,
int
timeout)
3
{
4
unsigned
long
now, token
=
dst
->
rate_tokens;
5
int
rc
=
0
;
6
7
now
=
jiffies;
8
token
+=
now
-
dst
->
rate_last;
9
dst
->
rate_last
=
now;
10
if
(token
>
XRLIM_BURST_FACTOR
*
timeout)
11
token
=
XRLIM_BURST_FACTOR
*
timeout;
12
if
(token
>=
timeout)
{
13
token
-=
timeout;
14
rc
=
1
;
15
}
16
dst
->
rate_tokens
=
token;
17
return
rc;
18
}
dst为目标路由缓存,timeout为允许发送的超时(单位为jiffies),dst->rate_tokens记录令牌的个数,当令牌个数不小于timeout时,则减少timeout并允许发送一个消息;反之则不能发送,需等到令牌个数累积到大于timeout时才能发送,但是不能无限大,否则就会导致在一个可能很短的timeout内,发送远多于6个的消息,引起ICMP风暴,所以这里限制了令牌的最大值为XRLIM_BURST_FACTOR*timeout即6倍的超时,也就是说在一个timeout内,最多能发送6个差错消息。
重定向限速
路由子系统使用ip_rt_send_redirect来发送重定向消息,定义在ipv4/route.c中,该函数内部调用icmp_send实现,在它的限速基础上,使用
指数回退算法
控制发送速率。
1
void
ip_rt_send_redirect
(
struct
sk_buff
*
skb)
2
{
3
struct
rtable
*
rt
=
skb_rtable(skb);
4
5
6
/**/
/*
No redirected packets during ip_rt_redirect_silence;
7
* reset the algorithm.
8
*/
9
if
(time_after(jiffies, rt
->
u.dst.rate_last
+
ip_rt_redirect_silence
))
10
rt
->
u.dst.rate_tokens
=
0
;
11
12
/**/
/*
Too many ignored redirects; do not send anything
13
* set u.dst.rate_last to the last seen redirected packet.
14
*/
15
if
(rt
->
u.dst.rate_tokens
>=
ip_rt_redirect_number
)
{
16
rt
->
u.dst.rate_last
=
jiffies;
17
return
;
18
}
19
20
/**/
/*
Check for load limit; set rate_last to the latest sent
21
* redirect.
22
*/
23
if
(rt
->
u.dst.rate_tokens
==
0
||
time_after(jiffies,
(rt
->
u.dst.rate_last
+
(
ip_rt_redirect_load
<<
rt
->
u.dst.rate_tokens))))
{
24
icmp_sen
d
(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt
->
rt_gateway);
25
rt
->
u.dst.rate_last
=
jiffies;
26
++
rt
->
u.dst.rate_tokens;
27
28
}
29
}
重定向差错使用ip_rt_redirect_silence(默认为(HZ/50)<<10)、ip_rt_redirect_number(默认为9)和ip_rt_redirect_load(默认为HZ/50)3个量来控制发送的速率;rt->u.dst.rate_last记录上次发送的时间,rt->u.dst.rate_tokens累计发送总数,最大值为ip_rt_redirect_number;当两次发送的时间间隔超过ip_rt_redirect_silence或ip_rt_redirect_load<<rt->u.dst.rate_tokens,并且发送总数不超过ip_rt_redirect_number时,才允许发送一个,这样一来,在ip_rt_redirect_silence间隔内,每次发送的超时呈2的指数增长,达到了变减速发送的效果,直到总数达到ip_rt_redirect_number时停止发送,这是因为源主机可能忽略了重定向消息所以停止发送;当ip_rt_redirect_silence时间过后,又允许发送了,这是因为认为源主机没有更新路由所以又需要发送。
posted on 2015-05-18 19:52
春秋十二月
阅读(2760)
评论(0)
编辑
收藏
引用
所属分类:
Network
只有注册用户
登录
后才能发表评论。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
相关文章:
基于X509证书的身份认证思考小结
使用HiRedis实现自动重连Redis
基于ENet实现可靠UDP通信的同步模型
总结网络路由走向诊断方法
深入理解SSL/TLS技术内幕
一种拦截Linux原始套接字IO的方法
一种P2P代理中TCP连接调度的方法
TCP分组丢失时的状态变迁
Linux ICMP消息的产生与转换
Linux套接字与虚拟文件系统(2):操作和销毁
网站导航:
博客园
IT新闻
BlogJava
博问
Chat2DB
管理
本博客所有随笔均为原创,因为不定期维护更新,所以转载请注明出处,如有问题和建议,请留言或评论,发表您的宝贵意见,藉此平台以分享交流、共同进步。
联系方式:微信theory-math
<
2011年8月
>
日
一
二
三
四
五
六
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
常用链接
我的随笔
我的评论
我参与的随笔
留言簿
(63)
给我留言
查看公开留言
查看私人留言
随笔分类
(155)
Algorithm(43)
C/C++(24)
Compiler(25)
Compute Theory(5)
Database(4)
Network(17)
Opensrc(13)
System(24)
随笔档案
(156)
2024年11月 (1)
2024年9月 (1)
2024年8月 (2)
2024年6月 (1)
2024年5月 (1)
2024年4月 (1)
2024年3月 (2)
2024年2月 (2)
2023年12月 (1)
2023年11月 (2)
2023年10月 (2)
2023年9月 (37)
2021年12月 (1)
2021年10月 (1)
2021年9月 (1)
2021年2月 (1)
2020年5月 (3)
2020年4月 (1)
2019年11月 (4)
2019年7月 (1)
2018年11月 (1)
2017年12月 (1)
2016年12月 (1)
2016年11月 (2)
2016年10月 (1)
2016年9月 (1)
2016年8月 (3)
2016年7月 (4)
2016年5月 (1)
2015年10月 (2)
2015年9月 (1)
2015年6月 (2)
2015年5月 (3)
2015年2月 (1)
2015年1月 (1)
2014年12月 (2)
2014年4月 (2)
2014年3月 (1)
2014年1月 (1)
2013年10月 (1)
2013年9月 (1)
2013年8月 (3)
2013年5月 (1)
2013年3月 (1)
2012年11月 (1)
2012年9月 (3)
2012年8月 (1)
2012年7月 (1)
2012年6月 (5)
2012年5月 (3)
2011年12月 (5)
2011年11月 (1)
2011年10月 (5)
2011年8月 (7)
2011年7月 (6)
2011年6月 (6)
2010年6月 (1)
2009年12月 (1)
2009年8月 (1)
2009年7月 (1)
2009年6月 (1)
2009年4月 (3)
文章分类
(30)
诗词作品集(30)
关注的开源项目
LLVM
编译系统
nginx
高性能Web服务器
OpenSSL
密码学库
suricata
网络IPS引擎
最新随笔
1. 关于椭圆曲线的验证计算
2. 不可约多项式判别算法的改正
3. 论证有限域上平方根的求解
4. 求解离散对数问题的Terr算法
5. 简单私钥加密构造的验证及安全性分析
6. 二元有限域及其扩域上的计算
7. 简单连分数攻击RSA的迭代次数分析
8. 有限循环群的结构及生成元的判定
9. 混合线性同余发生器的引理验证
10. Blum数的基本定理及应用
积分与排名
积分 - 403642
排名 - 57
最新评论
1. re: 一种拦截Linux原始套接字IO的方法[未登录]
很有前途和很有钱途啊。
--chipset
2. re: 一种拦截Linux原始套接字IO的方法[未登录]
@chipset
是的
--春秋十二月
3. re: 一种拦截Linux原始套接字IO的方法[未登录]
工作是做网络安全?
--chipset
4. re: 一种使用函数指针实现状态机的方法
函数指针实现状态机
--linda
5. re: 多标签视图类CTabView的设计实现
为啥代码缺少一些呢,给新手个完整点的啊
--pekingliu
6. re: 工作线程与消息循环
从消息队列取出消息 mark了
--mmocake
7. re: 一种简单的跨平台套接字管道
评论内容较长,点击标题查看
--IT搬运工
8. re: 一种简单的跨平台套接字管道
windows仅支持af_init和af_init6地址族有错别字么?
af_init和af_init6
--IT搬运工
9. re: Shell应用(8):使用awk定位反汇编输出[未登录]
厉害
--Chipset
10. re: TCP分组丢失时的状态变迁
不错
--Binky
阅读排行榜
1. 基于OpenSSL实现的安全连接(13777)
2. 字符串16进制显示(12803)
3. 基于boost asio实现的ssl socket框架(12205)
4. Linux套接字与虚拟文件系统(1):初始化和创建(8559)
5. 关于数据库的一些学习研究心得(8053)
6. 使用CString GetBuffer自适应获取计算机名称(7925)
7. 使用正则表达式解析URL(7845)
8. basic_string内存泄露问题之分析解决(7646)
9. Shell应用(4): 使用sed删除行尾的^M字符(7592)
10. nginx iocp(1):tcp异步连接(7504)
评论排行榜
1. basic_string内存泄露问题之分析解决(19)
2. 求单向链表倒序第m个元素(11)
3. 基于顺序存储实现的多叉树(1):深度优先存储(9)
4. 字符大小写转换(7)
5. 字符串16进制显示(6)
6. 面向对象锁框架的设计与实现(6)
7. Shell应用(4): 使用sed删除行尾的^M字符(5)
8. 工作线程与消息循环(5)
9. 使用正则表达式解析URL(5)
10. 十进制整数千位分隔符(4)