内容简介:最近想要在一个内核里的小聊天服务器练手用,现在写完的内容,可以作为一个通讯协议的监控程序使用。
本文作者:rochek,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。
这是一个简易的通信协议的hook,可以在FreeBSD11上使用。
简介
最近想要在一个内核里的小聊天服务器练手用,现在写完的内容,可以作为一个通讯协议的监控程序使用。
这里是我的BLOG,如果这个项目有更新,应该会发在这里。
使用Hux的模板做的Github pages,轻拍(捂脸)
使用的原理很简单,替换掉原有的协议处理函数,把协议载荷内的信息打印到dmesg内。
现在仅仅处理了UDP的内容。TCP,ICMP稍作改动应该也可以监控。
实现
1. 替换通信协议的处理函数
在FreeBSD内核内,通信协议的protosw是这样定义的。
ICMP
{
.pr_type = SOCK_RAW,
.pr_domain = &inetdomain,
.pr_protocol = IPPROTO_ICMP,
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
.pr_input = icmp_input,
.pr_ctloutput = rip_ctloutput,
.pr_usrreqs = &rip_usrreqs
},
TCP
{
.pr_type = SOCK_STREAM,
.pr_domain = &inetdomain,
.pr_protocol = IPPROTO_TCP,
.pr_flags = PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD,
.pr_input = tcp_input,
.pr_ctlinput = tcp_ctlinput,
.pr_ctloutput = tcp_ctloutput,
.pr_init = tcp_init,
.pr_slowtimo = tcp_slowtimo,
.pr_drain = tcp_drain,
.pr_usrreqs = &tcp_usrreqs
},
UDP
{
.pr_type = SOCK_DGRAM,
.pr_domain = &inetdomain,
.pr_protocol = IPPROTO_UDP,
.pr_flags = PR_ATOMIC|PR_ADDR,
.pr_input = udp_input,
.pr_ctlinput = udp_ctlinput,
.pr_ctloutput = ip_ctloutput,
.pr_init = udp_init,
.pr_usrreqs = &udp_usrreqs
},
想要获取通信协议mbuf内的信息,替换掉pr_input即可。
一般的做法是在内核组件载入时,把通信协议对应的pr_input替换,在卸载时还原。
case MOD_LOAD:
/* Replace udp_input with udp_input_hook. */
inetsw[ip_protox[IPPROTO_UDP]].pr_input = udp_input_hook;
break;
当然也可以写一个应用层控制程序,向这个内核模块发送某段数据时,内核模块才替换pr_input
2. 设计hook函数
作为hook时使用的函数,需要和原有函数相同的定义。
例如这样:
int udp_input_hook(struct mbuf **mp, int *offp, int proto);
经过以上这两段,UDP报文的处理函数就直接进入了我们自定义的函数udp_input_hook()内了。
作为一个通信协议的处理函数,首先需要处理mbuf内UDP的信息确实存在。
if (iphlen > sizeof (struct ip)) {
ip_stripoptions(m);
iphlen = sizeof(struct ip);
}
为了保证之后有UDP信息,UDP头和IP头的长度一定要保证下来。
剩余长度不满足UDP头的话,接下来就没办法处理了,所以这里把数据返回。
ip = mtod(m, struct ip *);
if (m->m_len < iphlen + sizeof(struct udphdr)) {
if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == NULL) {
UDPSTAT_INC(udps_hdrops);
return (IPPROTO_DONE);
}
ip = mtod(m, struct ip *);
}
然后,获取UDP头
uh = (struct udphdr *)((caddr_t)ip + iphlen);
可以从UDP头内获取一些所需要的信息,结合在上一步获取的ip头,就可以获取到这个包的具体信息了。
例如发送地址,源端口号,目的端口号等等。
可以把这些都记录下来,以后扩展功能用。
再剥离头
m->m_len -= iphlen + sizeof(struct udphdr); m->m_data += iphlen + sizeof(struct udphdr);
这样,当前m_data的位置就是UDP数据区的位置了。
这个位置就是UDP载荷的信息。
之前说的,直接打印到dmesg内。
printf("load=%s \n", m->m_data);
为了让hook后的通讯协议正常工作,需要把mbuf返回给原来的处理函数。否则这个机器的UDP协议就没法正常运行了。
首先,需要恢复mbuf。
m->m_len += iphlen + sizeof(struct udphdr); m->m_data -= iphlen + sizeof(struct udphdr);
再返回给原处理函数
return udp_input(mp, offp, proto);
后记
这样,就完成了把每次pr_input都打印出的一个内核协议的hook。
因为最后返回给了原有的协议栈,所以不影响原有处理功能。
这个hook,我原本的计划是作为一个非阻塞的recive_from(),稍作改动,可以做其它事情。
比如,接着写下去,做一个基于UDP的特殊协议等等。
本文作者:rochek,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 网络通信2:TCP简单通信
- 网络通信3:TCP交互通信
- 如何在ASP.NET Core中使用SignalR构建与Angular通信的实时通信应用程序
- Electron 使用串口通信
- 进程间通信---共享内存
- 微服务通信策略
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
阿里巴巴正传:我们与马云的“一步之遥”
方兴东、刘伟 / 江苏凤凰文艺出版社 / 2015-1 / 45.00
十几年来,方兴东与马云每年一次,老友聚首,开怀畅谈,阿里上市前,作者再次与马云深度对话,阿里上市前的布局,深入探讨了一系列人们关心的话题。 本书忠实记录了阿里壮大、马云封圣的历史。作者通过细致梳理和盘点,对阿里巴巴的15年成长史进行了忠实回顾。从海博翻译社到淘宝网,从淘宝商城到天猫,从支付宝到阿里云计算,从拉来软银的第一笔投资到纽交所上市,作者对其中涉及到的人物、细节都有生动展现;对于马云、......一起来看看 《阿里巴巴正传:我们与马云的“一步之遥”》 这本书的介绍吧!