netfilter

内核网络编程

网络协议数据结构inet_protosw

Linux-2.6.26.3/net/ipv4/af_inet.c文件中有一个名为inet_init()的函数对协议进行了初始化。inet_init()函数使用proto_register()函数来注册每个内嵌协议。

软中断CPU报文队列及其处理

  • Linux内核网络协议层的层间传递手段——软中断

软中断机制的核心元素:

  • 软中断状态:是否有触发的软中断未处理
  • 软中断向量表:包含两个成员变量,一个是处理此软中断的回调函数,另一个是处理时所需的参数。
  • 软中断守护内核线程:内核建立一个内核线程ksoftirqd来轮询软中断状态,调用软中断向量表中的软中断回调函数处理中断

中断事件处理过程:

  1. 中断事件发生
  2. 调用raise_softirq()函数设置对应的中断标记位,触发中断事务
  3. 检测中断状态寄存器的状态
  4. ksoftirqd通过查询发现某一软中断事务发生之后,通过软中断向量表调用软中断程序action

软中断使用方法

Linux系统最用同时注册32个软中断,目前系统使用了6个软中断。其中一个为taskle机制,该机制用来实现下半部,描述软中断的核心数据结构为中断向量表,其定义如下:

struct softirq_action
{ void (*action)(struct softirq_action *); void *data;
};
  • action:软中断服务程序
  • data:服务程序输入参数

sk_buff结构

因为内核层和用户层在网络方面的差别很大,在内核的网络层的sk_buff结构占有重要的地位,几乎所有的处理与此结构有关系。

sk_buff主要成员:

socket数据在内核中接收和发送

socket数据在内核中的流程主要包括初始化、销毁、接收和发送网络数据源。其过程设计网卡驱动、网络协议栈和应用层的接口函数。

  • socket()初始化:创建socket()需要传递family、type、protocol这三个参数。
  • 创建socket()其实就是创建一个socket实例,然后创建一个文件描述符结构。创建套接字文件描述符会互相建立关联,即建立相互连接的的指针,并且初始化这些文件的读写操作映射到read()、write()函数上来。

  • 在初始化套接字的时候,同时初始化socket的操作函数(proto_ops结构)

  • 创建socket的同时还创建sock结构的数据空间。还会初始化三个队列:receive_queue,send_queue,backlog_queue。

  • 接收网络数据recv():

网络数据接收依次经过网卡驱动和协议栈程序。

  • 发送网络数据send():

linux对网络数据的发送过程的处理与接收过程相反。在一端对socket进行write()的过程中。首先会把write的字符串缓冲区整理成msghdr的数据结构形式,然后调用sock_sendmsg()把msghdr的数据传送至inet层。

msghdr结构中数据区的每个数据包,创建sk_buff结构,填充数据,挂至发送队列。一层层往下层协议传递。以下的每层协议将不再对数据进行复制,而是对sk_buff结构直接进行操作

内核模块编程

内核模块编程和典型的应用程序的区别:

典型应用有一个main程序,而内核模块需要一个初始化函数和清理函数,在向内核中插入模块时调用初始化函数,卸载内核模块时调用清理函数。

加载内核相对于直接编写内核模块有很大方便性:

  • 不用重新编译内核
  • 可以动态加载和卸载,调试使用方便。

Hello,World

编写C语言程序:

//必要的头文件
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
//模块许可证声明(必须)
MODULE_LICENSE("Dual BSD/GPL");
//模块加载函数(必须)
static int hello_init(void)
{printk(KERN_ALERT "Hello World enter/n");return 0;
}
//模块卸载函数(必须)
static void hello_exit(void)
{printk(KERN_ALERT "Hello World exit/n");
}
//模块的注册
module_init(hello_init);
module_exit(hello_exit);
//声明模块的作者(可选)
MODULE_AUTHOR("XXX");
//声明模块的描述(可选)
MODULE_DESCRIPTION("This is a simple example!/n");
//声明模块的别名(可选)
MODULE_ALIAS("A simplest example");

编写makefile文件:

obj-m += hello.o
#generate the path
CURRENT_PATH:=$(shell pwd)
#the current kernel version number
LINUX_KERNEL:=$(shell uname -r)
#the absolute path
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
#complie object
all:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
#clean
clean:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

执行make命令能得到

以上这些文件,使用sudo insmod Hello.ko来加载内核:

但是能发现并没有任何消息提示,这是因为printk函数并不是在命令行将信息打印而是在系统日志里面,需要使用指令dmesg进入系统日志:

也可以使用lsmod查看内核依赖关系:

最后,输入rmmod指令卸载内核

内核模块的基本架构

  1. 模块初始化

自动调用模块的的初始化函数,进行模块的初始化,主要是资源申请。

  1. 模块清楚函数

使用命令rmmod卸载内核模块,模块清除函数自动调用。主要状态重置和资源释放。

  1. 模块许可声明、作者、模块描述等信息

并不是强制要求必须声明。内核可以识别以下四种许可方式:GPLa Dual BSD/GPLa Dual MPL/GPLa Proprietary。如果没有采用以上许可证方式的声明则假定为私有的,内核加载这种模块会被“污染”。

  • MODULE_AUTHOR:作者描述模块
  • MODULE_DESCRIPTION:模块用途的简短描述
  • MODULE_VERSION:模块版本号
  • MODULE_AVIAS:模块别名

内核加载模块过程


内核卸载模块过程


netfilter的五个钩子函数

在IP包的IPv4协议栈上的传递过程中,有五个检查点,并且各引入了一对NF_HOOK()宏函数的一个响应的调用:

  • PREROUTING:在报文做路由以前执行
  • LOCAK-IN:在报文转向另一个NIC(网卡)以前执行
  • FORWARD:在报文流出以前执行
  • LOCAL-OUT:在流入本地的报文做路由以后执行
  • POSTROUTING:在本地报文做流出路由之前执行

利用这5个参考点,查阅用户注册的回调函数,根据用户定义的回调函数来监视进出的网络数据包,是netfilter的基本实现框架。

netfilter定义了一个全局变量来存储用户的回调函数:

struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];

其中,NPROTO是协议类型,可以是TCP、UDP或者IP协议。NF_MAX_HOOKS是挂接的钩子最大数量。

以上介绍的五个检查点对应五个钩子函数。

  • NF_IP_PRE_ROUTING:
  • NF_IP_FORWARD:
  • NF_IP_POST_ROUTING:
  • NF_IP_LOCAL_IN:
  • NF_IP_LOACL_OUT:

如果是要做包过滤,需要用到NF_IP_LOCAL_IN钩子函数。


NF_HOOK宏

netfilter的框架是在协议栈处理过程中调用NF_HOOK(),插入处理过程来实现的。

#ifdef CONFIG_NETFILTER
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
#else
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#endif /*CONFIG_NETFILTER*/

以上为NF_HOOK()函数的定义。从该函数宏可知,当编译了netfilter时(#ifdef CONFIG_NETFILTER )就会调用nf_hook,slow()函数。如果没有的话则调用NF_HOOK宏中的参数okfn。


钩子的处理规则

netfilter的钩子函数的返回值可以为NF_ACCEPT、 NF_DROP、 NF_STOLEN、NF_QUERE、 NF_REPEAT

  • nf_accept:继续传递,保持和原来传输的一致
  • nf_drop:丢弃包,不再继续传递
  • nf_stolen:接管包,不再继续传递
  • nf_quere:队列化包(通常是为用户空间处理做准备)
  • nf_repeat:再次调用这个钩子

注册/注销钩子

注册和注销钩子函数的接口主要有:nf_register_hook、nf_unregister_hook、nf_register_sockopt 、nf_unregister_sockopt

nf_hook_ops结构

struct nf_hook_ops
{ struct list_head list;  //钩子链表nf_hookfn *hook;         //钩子处理函数struct module           //模块所有者 int pf;                 //钩子的协议族int hooknum;            //钩子的位置值int priority;           //钩子的优先级,默认情况为继承优先级
};

typedef unsigned int nf_hookfn(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *));

okfn()函数是当回调函数为空时,netfilter调用的处理函数。

  • 注册钩子

void nf_register_net_hook(struct net *net, const struct nf_hook_ops *ops);

  • 注销钩子

void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *ops);

钩子函数的Hello,World

#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <net/tcp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>static struct nf_hook_ops nfhoLocalIn; //定义实现钩子函数的结构体
MODULE_LICENSE("Dual BSD/GPL");unsigned int hello_hookfn(void* priv, struct sk_buff* skb, const struct nf_hook_state* state)  //回调函数
{printk(KERN_ALERT "Hello World Hook\n");return NF_ACCEPT;
}
int init_module()   //初始化模块
{nfhoLocalIn.hook = hello_hookfn;  //构建结构体nfhoLocalIn.pf = PF_INET;nfhoLocalIn.priority = NF_IP_PRI_FIRST;nf_register_net_hook(&init_net, &nfhoLocalIn); //注册钩子printk("My nf register\n");return 0;
}
void cleanup_module()
{nf_unregister_net_hook(&init_net, &nfhoLocalIn);   //注销钩子printk("My nf unregister\n");
}

Linux内核网络编程相关推荐

  1. 显示驱动包含在Linux内核层,驱动程序层(上) - Linux内核--网络栈实现分析_Linux编程_Linux公社-Linux系统门户网站...

    经过前面两篇博文的分析,已经对Linux的内核网络栈的结构有了一个模糊的认识,这里我们开始从底层开始详细分析Linux内核网络栈的实现.由于这是早期版本,代码的层次隔离做的还不是很好,这里说是从底层分 ...

  2. Linux内核网络栈1.2.13-socket.c函数概述

    参考资料 <<linux内核网络栈源代码情景分析>> socket常用函数概述 根据socket提供的常用的库函数,socket,read,write等函数, 执行的过程 in ...

  3. 深入Linux内核网络堆栈

    前一段时间看到这篇帖子,确实很经典,于是翻出了英文原版再读,顺便再翻译出来供大家学习,这篇文章的中文版也早都有了,不过出于完全理解的目的,我还是将它翻译了出来,加进了自己的代码,虽然在上一周的翻译过程 ...

  4. Linux内核网络性能优化

    Linux内核网络性能优化 1. 前言 2. Linux网络协议栈 3. DPDK 4. XDP 4.1 XDP主要的特性 4.2 XDP与DPDK的对比 4.3 应用场景 5. CPU负载均衡 5. ...

  5. 基于linux epoll网络编程细节处理丨epoll原理剖析

    epoll原理剖析以及三握四挥的处理 1. epoll原理详解 2. 连接的创建与断开 3. epoll如何连接细节问题 视频讲解如下,点击观看: 基于linux epoll网络编程细节处理丨epol ...

  6. Linux多线程网络编程要义丨epoll与reactor原理

    linux多线程网络编程要义 1. epoll原理剖析 2. 单reactor原理以及应用 3. 多reactor原理以及应用 [Linux服务器系列]Linux多线程网络编程要义丨epoll与rea ...

  7. Linux内核网络协议栈流程及架构

    文章目录 Linux内核网络报文处理流程 Linux内核网络协议栈架构 Linux内核网络报文处理流程 linux网络协议栈是由若干个层组成的,网络数据的处理流程主要是指在协议栈的各个层之间的传递. ...

  8. 【Linux】网络编程三:TCP通信和UDP通信介绍及代码编写

    参考连接:https://www.nowcoder.com/study/live/504/2/16. [Linux]网络编程一:网络结构模式.MAC/IP/端口.网络模型.协议及网络通信过程简单介绍 ...

  9. linux和网络编程笔记

    第一部分.章节目录 3.4.1.程序的开始和结束 3.4.2.进程环境 3.4.3.进程的正式引入 3.4.4.fork创建子进程 3.4.5.父子进程对文件的操作 3.4.6.进程的诞生和消亡 3. ...

  10. 《Linux内核驱动模块编程指南》

    Foreword Table of Contents 作者声明 版本和注意 感谢 译者注 作者声明 <Linux内核驱动模块编程指南>最初是由Ori Pomerantz为2.2版本的内核编 ...

最新文章

  1. JTable动态显示隐藏列
  2. android黑科技系列——静态分析技术来破解Apk
  3. 【杂谈】新手如何掌握深度学习模型?赠书2本,星球券10张
  4. Exchange Server2010系列之七:多邮箱搜索找出神秘邮件的幕后黑手
  5. 浏览器了解(二)HTML解析过程
  6. 20应用统计考研复试要点(part8)--应用多元分析
  7. linux的locate工具,linux文本查找工具之locate、find
  8. vue全家桶+Koa2开发笔记(3)--mongodb
  9. Visual Studio Code 编辑器使用
  10. MyBatis返回结果不稳定
  11. docker入门2---docker的初体验
  12. vi编辑器使用技巧篇1
  13. 计算机工程工艺,中国计算机学会第十届计算机工程与工艺学术年会.pdf
  14. Win10快捷键模式退出的方法
  15. PDFObject无法加载远程url和不支持IE浏览器解决方案
  16. 统信系统安装京瓷打印机驱动步骤 针对京瓷系列复合机的UOS操作系统用户使用说明
  17. 脚本文件BAT入门(1)
  18. DWG中注记平移问题
  19. 视频监控ai分析系统 yolo
  20. Ubuntu 10.04内核源码树的编译和安装

热门文章

  1. 【FPGA——协议篇】:I2C总线协议详解+verilog源码
  2. 递归算法经典实例python-python实现汉诺塔递归算法经典案例
  3. QQ登录超时,请检查您的网络或本机防火墙设置【00001】
  4. jieba java_【NLP】【一】中文分词之jieba
  5. GPU机器无法使用GPU
  6. mxf转换工具(Aiseesoft MXF Converter) v9.2.36
  7. /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o:在函数‘_start’中:(.text+0x20):对‘main’未
  8. LOIC低轨道离子拒绝服务攻击
  9. 微信小程序毕业设计和毕业论文怎么写,答辩流程是怎样的?
  10. Windows系统字体和系统应用字体