Linux 内核源码分析---内核 Netlink 套接字

news2024/9/21 2:48:26

linux 内核一直存在的一个严重问题就是内核态和用户态的交互的问题,对于这个问题内核大佬们一直在研究各种方法,想让内核和用户态交互能够安全高效的进行。如系统调用,proc,sysfs 等内存文件系统,但是这些方式一般都比较简单,只能在用户空间轮询访问内核的变化,内核的变化无法主动的推送出来

Netlink 套接字接口最初是 Linux 内核 2.2 引入的,名为AF_NETLINK套接字,提供一种更为灵活的用户空间进程与内核间通信方法,替代IOCTL。它运行模型非常简单,只需要使用套接字 API 打开并注册一个 Netlink 套接字,它就会处理与内核 Netlink 套接字的双向通信。

目前 netlink 的这种机制被广泛使用在各种场景中,在 Linux 内核中使用 netlink 进行应用与内核通信的应用很多;包括:路由 daemon(NETLINK_ROUTE),用户态 socket 协议(NETLINK_USERSOCK),防火墙(NETLINK_FIREWALL),netfilter 子系统(NETLINK_NETFILTER),内核事件向用户态通知(NETLINK_KOBJECT_UEVENT)等。

优势:
(1)使用 netlink 套接字时不需要轮询,用空间应用程序打开套接字,再调用 recvmsg(),如果没有来自内核的消息,就进入阻塞状态;
(2)内核可以主动向用户空间发送异步消息,而不需要用户空间来触发;
(3)netlink 套接字支持组播传输。
(4)要在用户空间中创建 netlink 套接字,可使用系统调用 socket(),netlink 套接字就可以是 SOCK_RAW 套接字,也可以是 SOCK_DGRAM 套接字。

为什么选择netlink套接字?

  • netlink 套接字支持多播,且一个进程可以将消息多播到netlink地址组。
  • netlink 提供BSD套接字样式的API。
  • netlink 套接字是异步的,并提供套接字的消息排队规则。
  • 要支持任何新的特征,只需要实现对应的协议类型。

Netlink 协议是一种在 RFC 3549 中定义的进程间通信机制,为用户空间和内核以及内核的有些部分之间提供双向通信信道,是对标准套接字实现的扩展。Netlink 协议实现基本是位于net/netlink 下,包含4个文件:
在这里插入图片描述

事实上最常用的是 af_netlink 模块,它提供 netink 内核套接字 APl,而 genetlink 模块提供了新的通用 netlink API。监视接口模块 diag(diag.c)提供的API用于读写有关的 netlink 套接字信息。
从理论原则来讲,netlink 套接字可用于在用户空间进程间通信(包括发送组播消息),但通常不这样做,而且这也不是开发 netlink 套接字初衷。UNIX 域套接字提供用于进程间通信(IPC) 的 API,被广泛用于两个用户空间进行间的通信。

一般来说用户空间和内核空间的通信方式有三种:/procioctlNetlink。而前两种都是单向的,而 Netlink 可以实现双工通信

内核和用户空间中创建 Netlink 套接字
在这里插入图片描述

netlink 数据结构
在这里插入图片描述

1、创建 netlink套接字源码、注册操作、数据包发送操作

在内核网络栈中,可创建 netlink 套接字如下:
在这里插入图片描述

使用 netlink 内核套接字,首先需要注册它:
在这里插入图片描述

数据包的实际发送工作是由通用 Netlink 方法nlmsg_notify()完成:
在这里插入图片描述

Netlink消息必须采用特定的格式,此格式是在RFC 3549中进行规定的。Netlink消息 的开头是长度固定的 Netlink报头,其后是有效载荷。
netlink 数据包的开头都是由结构 nlmsghdr 表示 netlink 消息报头,整个长度为16字节,包括5个字段如下
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
路由选择中添加/删除路由选择条目:
添加ip route add 参数
删除ip route del ip地址
使用 iproute2 命令ip来监视网络事件:ip monitor route

创建和发送通用 Netlink 消息:
通用 Netlink 消息的开头是一个 Netlink 报头,接下来是通用 Netlink 消息报头以及可选的用户特定报头,然后是可选的有效载荷,内核通用 Netlink 消息 genlmsghdr 结构源码如下
在这里插入图片描述
在这里插入图片描述

套接字监视接口
netlink 套接字sock_diag提供一个基于 netlink 子系统,可用于获取有关套接字的信息,在内核中添加它是指在Linux用户空间中支持检查点/恢复功能(CRIU)。要支持这项功能,还需要有关套接字的其他数据。创建netlink内核套接字sock_diag,具体源码如下
在这里插入图片描述

/****************************************
* Author: vico
* Date: 2021-06-26
* Filename: netlink_test.c
* Descript: netlink of kernel
* Kernel: 3.10.0-327.22.2.el7.x86_64
* Warning:
******************************************/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/netlink.h>

#define NETLINK_TEST     30
#define MSG_LEN            125
#define USER_PORT        100

MODULE_LICENSE("GPL");
MODULE_AUTHOR("vico");
MODULE_DESCRIPTION("netlink protocol example");

struct sock *nlsk = NULL;
extern struct net init_net;

int send_usrmsg(char *pbuf, uint16_t len)
{
    struct sk_buff *nl_skb;
    struct nlmsghdr *nlh;

    int ret;

    /* 创建sk_buff 空间 */
    nl_skb = nlmsg_new(len, GFP_ATOMIC);
    if(!nl_skb)
    {
        printk("\nError:netlink alloc failure.\n\n");
        return -1;
    }

    /* 设置netlink消息头部 */
    nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0);
    if(nlh == NULL)
    {
        printk("\nError:nlmsg_put failaure. \n\n");
        nlmsg_free(nl_skb);
        return -1;
    }

    /* 拷贝数据发送 */
    memcpy(nlmsg_data(nlh), pbuf, len);
    ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT);

    return ret;
}

static void netlink_rcv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh = NULL;
    char *umsg = NULL;
    char *kmsg = "Hello vico users program.";

    if(skb->len >= nlmsg_total_size(0))
    {
        nlh = nlmsg_hdr(skb);
        umsg = NLMSG_DATA(nlh);
        if(umsg)
        {
            printk("kernel recv from user: %s\n", umsg);
            send_usrmsg(kmsg, strlen(kmsg));
        }
    }
}

struct netlink_kernel_cfg cfg = {
        .input  = netlink_rcv_msg, /* set recv callback */
};

int test_netlink_init(void)
{
    /* create netlink socket */
    nlsk = (struct sock *)netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
    if(nlsk == NULL)
    {
        printk("\nError:netlink_kernel_create error !\n");
        return -1;
    }
    printk("\ntest_netlink_init\n");

    return 0;
}

void test_netlink_exit(void)
{
    if (nlsk){
        netlink_kernel_release(nlsk); /* release ..*/
        nlsk = NULL;
    }
    printk("test_netlink_exit!\n");
}

module_init(test_netlink_init);
module_exit(test_netlink_exit);
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>

#define NETLINK_TEST    30
#define MSG_LEN         125
#define MAX_PLOAD       125

typedef struct _user_msg_info
{
    struct nlmsghdr hdr;
    char  msg[MSG_LEN];
} user_msg_info;

int main(int argc, char **argv)
{
    int skfd;
    int ret;
    user_msg_info u_info;
    socklen_t len;
    struct nlmsghdr *nlh = NULL;
    struct sockaddr_nl saddr, daddr;
    char *umsg = "Hello Netlink protocol.";

    /* 创建NETLINK socket */
    skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if(skfd == -1)
    {
        perror("\nError:Create socket error.\n");
        return -1;
    }

    memset(&saddr, 0, sizeof(saddr));
    saddr.nl_family = AF_NETLINK; //AF_NETLINK
    saddr.nl_pid = 100;  //端口号(port ID)
    saddr.nl_groups = 0;
    if(bind(skfd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0)
    {
        perror("\nError:bind() error.\n");
        close(skfd);
        return -1;
    }

    memset(&daddr, 0, sizeof(daddr));
    daddr.nl_family = AF_NETLINK;
    daddr.nl_pid = 0; // to kernel
    daddr.nl_groups = 0;

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));
    memset(nlh, 0, sizeof(struct nlmsghdr));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD);
    nlh->nlmsg_flags = 0;
    nlh->nlmsg_type = 0;
    nlh->nlmsg_seq = 0;
    nlh->nlmsg_pid = saddr.nl_pid; //self port

    memcpy(NLMSG_DATA(nlh), umsg, strlen(umsg));
    ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl));
    if(!ret)
    {
        perror("\nError:sendto error.\n");
        close(skfd);
        exit(-1);
    }
    printf("\nApplication-->Send kernel:%s\n\n", umsg);

    memset(&u_info, 0, sizeof(u_info));
    len = sizeof(struct sockaddr_nl);
    ret = recvfrom(skfd, &u_info, sizeof(user_msg_info), 0, (struct sockaddr *)&daddr, &len);
    if(!ret)
    {
        perror("\nError:recv form kernel error.\n");
        close(skfd);
        exit(-1);
    }

    printf("\nApplication-->From kernel:%s\n\n", u_info.msg);
    close(skfd);

    free((void *)nlh);
    return 0;
}

首先将编译出来的Netlink内核模块插入到系统当中(insmod netlink_test.ko):insmod netlink_test.ko

报错:insmod: ERROR: could not insert module netlink_test.ko: Operation not permitted
解决方案:http://t.csdnimg.cn/UhMSF

接着运行应用程序:./a.out

https://mp.weixin.qq.com/s/cJ8asff7eCVeFm2L4B3tLw
https://www.cnblogs.com/x_wukong/p/5920437.html
https://zhuanlan.zhihu.com/p/487961245
https://zhuanlan.zhihu.com/p/694289016

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2033272.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从今年的计算机视觉比赛看风向

记第一次参加CV比赛的经历-长三角&#xff08;芜湖&#xff09;人工智能视觉算法大赛-CSDN博客 去年参赛的记录里说了&#xff1a; 最近&#xff0c;同样的由芜湖举办的比赛又上线了&#xff0c;果然&#xff1a; 2023年是这些赛题&#xff0c;典型的CV&#xff1a; 今年变成…

如何高效记录并整理编程学习笔记?一个好的笔记软件往往可以达到事半功倍的学习效果 φ(* ̄0 ̄)

在编程学习的旅程中&#xff0c;良好的笔记习惯不仅是知识积累的基石&#xff0c;更是提升学习效率、巩固学习成果的关键。选择合适的笔记工具&#xff0c;并掌握其高效使用方法&#xff0c;对于每一位编程学习者而言都至关重要。本文将从笔记工具的选择角度出发&#xff0c;探…

Linux 中断机制(一)之中断和异常

目录 一、什么是中断1、概述2、中断的分类 二、中断和异常1、中断和异常2、中断的上下部3、异常4、APIC5、中断描述符表 三、软件实现 一、什么是中断 1、概述 中断&#xff08;interrupt&#xff09;是指在 CPU 正常运行期间&#xff0c; 由外部或内部事件引起的一种机制。 …

Miracast ——随时随地在Wi-Fi®设备上分享高清内容

Miracast 是一种无线显示技术&#xff0c;由 Wi-Fi 联盟开发&#xff0c;允许设备之间通过无线方式分享多媒体内容。 Wi-Fi CERTIFIED Miracast™支持在Miracast设备之间无缝显示多媒体内容。Miracast使用户能够通过无线连接在Wi-Fi设备之间分享多媒体内容&#xff0c;包括高分…

六西格玛绿带培训对企业有什么帮助?

六西格玛&#xff0c;这一源自摩托罗拉、风靡全球的管理哲学和方法论&#xff0c;以其严谨的数据分析、持续改进的流程优化理念&#xff0c;帮助无数企业实现了从“好”到“卓越”的跨越。而六西格玛绿带&#xff0c;作为这一体系中的中坚力量&#xff0c;是连接高层管理者与一…

Linux--C语言之分支结构

文章目录 一、分支结构&#xff08;一&#xff09;概念&#xff08;二&#xff09;条件构建1.关系表达式&#xff1a;2.逻辑表达式&#xff1a;3.常量/变量&#xff1a;值是否非0&#xff0c;取值&#xff08;0|1&#xff09; &#xff08;三&#xff09;选择结构的形式1.单分支…

QT容器组

目录 容器组 Group BoX&#xff08;组&#xff09; Scroll Area&#xff08;组滑动&#xff09; Tool Box&#xff08;分页显示&#xff09; Tab Widget&#xff08;也是分页显示&#xff09; Stacked widget&#xff08;也是分页&#xff09; Frame&#xff08;就一个框…

无字母数字webshell之命令执行

文章目录 无字母数字的webshell构造技巧php7下简单解决问题php5下解决问题glob开始操作 无字母数字的webshell构造技巧 <?php if(isset($_GET[code])){$code $_GET[code];if(strlen($code)>35){die("Long.");}if(preg_match("/[A-Za-z0-9_$]/",$c…

应对FingerprintJS反爬:Selenium的破解策略与技术详解

目录 引言 FingerprintJS技术概述 技术原理 应用场景 应对策略 高级解决方案 代码实现与案例分析 去除webdriver特征 使用Undetected_chromedriver 案例分析&#xff1a;爬取目标网站数据 结论 引言 在现代互联网环境中&#xff0c;网站反爬技术日益成熟&#xff0…

分布式知识总结(基本概念)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 基本概念 吞吐量 指系统在单位时间能够处理多少个请求 QPS 每秒…

【mars3d】加载pbf矢量瓦片的最佳方案介绍

矢量瓦片的目前最佳方案&#xff1a; 目前示例中提供了不同的矢量瓦片的加载方案 但是加载矢量瓦片pbf的最佳方案&#xff1a; 使用 TileServer GL 开源地图服务工具&#xff1a;https://github.com/maptiler/tileserver-gl &#xff0c; 它利用 MapLibre GL Native 进行服务…

day34——TCP和UDP的基础通信

一、网络通信之套接字 1.1 套接字通信原理 1.2 socket函数介绍 #include <sys/types.h> /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);功能&#xff1a;为通信创建一个端点&#xff0c;并返回该端点的文件描述…

Llama 3.1中文微调数据集已上线,超大模型一键部署

7 月的 AI 圈真是卷完小模型卷大模型&#xff0c;精彩不停&#xff01;大多数同学都能体验 GPT-4o、Mistral-Nemo 这样的小模型&#xff0c;但 Llama-3.1-405B 和 Mistral-Large-2 这样的超大模型让很多小伙伴犯了难。 别担心&#xff01;hyper.ai 官网在教程板块为大家提供了…

从AGV到立库,物流自动化的更迭与未来

AGV叉车 随着柔性制造系统的广泛应用&#xff0c;小批量、多批次的生产需求不断增强&#xff0c;“订单导向”生产已经成为趋势。这也让越来越多的企业认识到&#xff0c;产线的智能设备导入只是第一步&#xff0c;要想达到生产效率的最优解&#xff0c;物流系统的再优化必须提…

【redis的大key问题】

在使用 Redis 的过程中&#xff0c;如果未能及时发现并处理 Big keys&#xff08;下文称为“大Key”&#xff09;&#xff0c;可能会导致服务性能下降、用户体验变差&#xff0c;甚至引发大面积故障。 本文将介绍大Key产生的原因、其可能引发的问题及如何快速找出大Key并将其优…

Z 字形遍历二叉树

假设一个二叉树上各结点的权值互不相同。 我们就可以通过其后序遍历和中序遍历来确定唯一二叉树。 请你输出该二叉树的 ZZ 字形遍历序列----也就是说&#xff0c;从根结点开始&#xff0c;逐层遍历&#xff0c;第一层从右到左遍历&#xff0c;第二层从左到右遍历&#xff0c;…

Linux文本处理shell脚本

文本处理 在进行文本处理时&#xff0c;我们有一些常见的需求&#xff1a; 获取文本的行数、字数比较两段文本的不同之处查看文本的开头几行和最后几行在文本中查找字符串在文本中替换字符串 下面介绍如何在 shell 中做到这些事情。 文本统计&#xff1a;wc wc 是文本统计…

了解经典的 MPLS L3VPN 网络架构

1.多协议标签交换技术MPLS的概念 MPLS&#xff08;Multi-Protocol Label Switching&#xff0c;多协议标签交换技术&#xff09;,传统网络中就拥有了 3 种经典转发实现&#xff0c;它们分别是&#xff1a; L2 交换转发L2.5 标签转发L3 路由转发 MPLS 协议则作用于 L2.5 层&…

大数据-80 Spark 简要概述 系统架构 部署模式 与Hadoop MapReduce对比

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

布隆过滤器将应用Redis缓存使用量降低100倍

文章目录 背景布隆过滤器介绍定义工作原理数据结构&#xff1a; Redis布隆过滤器实战总结 背景 由于在业务中用到了Redis用于存储一些关系信息&#xff0c;且对应的请求量比较大&#xff0c;为了防止缓存击穿导致数据库压力过大&#xff0c;一般我们都会采用将不存在的内容存储…