一个FreeBSD下的通信协议监控程序

这是一个简易的通信协议的hook,可以在FreeBSD11上使用。

简介

最近想要在一个内核里的小聊天服务器练手用,现在写完的内容,可以作为一个通讯协议的监控程序使用。

这里是我的BLOG,如果这个项目有更新,应该会发在这里。

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 原创奖励计划,未经许可禁止转载。

本文分享自微信公众号 - FreeBuf(freebuf)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端技术探索

lnmp和lamp浅谈对比

LNMP(Linux-Nginx-MySQL-PHP)网站架构是目前国际流行的Web框架,该框架包括:Linux操作系统,Nginx网络服务器,MySQL数据库...

27010
来自专栏Java后端技术栈

Linux操作系统安装ELK stack日志管理系统--(2)Elasticsearch与Kibana的安装与使用

Linux操作系统安装ELK stack日志管理系统–(1)Logstash和Filebeat的安装与使用

14720
来自专栏Java成神之路

hive_学习_02_hive整合hbase(失败)

本文承接上一篇:hive_学习_01_hive环境搭建(单机) ,主要是记录 hive 整合hbase的流程

10220
来自专栏月色的自留地

把路由器改装成git服务器(OpenWRT环境的GIT服务器搭建)

在单位中,通常都标配了git服务器用来管理代码。 对于家庭或者小办公室,这种方式有点不经济。当然如果是开源项目就简单了,刚刚被微软收购的github是理想...

1.3K20
来自专栏Java成神之路

阿里大于短信服务_异常_01_InvalidTimeStamp.Expired

该错误含义为:用户发出请求的时间(由请求中携带的Timestamp参数标识)和服务器接收到请求的时间之差不在15分钟内。

11230
来自专栏idba

MySQL 压测工具之mydbtest

一 前言 本文介绍一款绿色免安装版本的数据库压测利器--mydbtest(mydbtest_linux64.bin,由楼方鑫大牛编写).该压测软件区别于sys...

23030
来自专栏后端技术探索

安全:nginx禁止ip访问, 只能通过域名访问

我的一个地方站(www.cxzaixian.com)曾经遇到过被无故断网的事情,阿里云给的原因是绑定了未备案的域名。

95530
来自专栏Java成神之路

Linux_学习_02_ 重启tomcat与查看tomcat日志

25050
来自专栏Java后端技术

你误解了Windows的文件后缀名吗?

  有很多的小伙伴对windows下的文件后缀名不能很好地理解作用和区别,更不用说高深的使用了,在这里给大家说一下这些文件后缀名到底有什么区别,有什么作用呢?

11310
来自专栏Linux技术资源分享

让Dock自动显示和隐藏程序坞不再延迟

前言 在EOS中,我是习惯将Docker隐藏的,想显示的时候就将鼠标移动过去,此时的Dock将即时显示出来,不延迟1微秒的时间,当然也可以搞成延迟。现在本已换...

43250

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励