linux C 使用netlink机制添加、删除 ip地址

该代码示例展示了如何使用netlink协议和Linux路由套接字来实现对网卡的IPv4或IPv6地址的添加和删除操作。通过调用socket、bind、sendmsg等系统函数,构建并发送RTM_NEWADDR消息到内核进行地址管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下代码是使用netlink机制实现对一个网卡添加删除ip地址的小demo,包括ipv4,ipv6地址。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <unistd.h>

#define BUFSIZE NLMSG_ALIGN(8192)

int main(int argc, char *argv[]) {
	if (argc != 2) {
		printf("./xxx 192.168.10.10\n");
		return 0;
		
	}
	
	
    int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (fd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_nl local_addr = {0};
    local_addr.nl_family = AF_NETLINK;
    local_addr.nl_pid = getpid();
    if (bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
        perror("bind");
        close(fd);
        exit(EXIT_FAILURE);
    }

    struct nlmsghdr *nh;
    char buf[BUFSIZE];
    memset(buf, 0, BUFSIZE);

    // 构造请求消息
    int ifindex = if_nametoindex("eth0"); // 指定接口名称
    struct in_addr addr;
    inet_pton(AF_INET, argv[1], &addr); // 指定 IP 地址
	/*
	如果是ipv6则用下面的代码
	struct in6_addr addr;
    inet_pton(AF_INET6, argv[1], &addr); // 指定 IP 地址
	*/
    struct {
        struct nlmsghdr nh;
        struct ifaddrmsg ifa;
        char attrbuf[512];
    } req;

    memset(&req, 0, sizeof(req));
    req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
    req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
    req.nh.nlmsg_type = RTM_NEWADDR;
    req.ifa.ifa_family = AF_INET;  // 如果是ipv6则换成AF_INET6 
    req.ifa.ifa_prefixlen = 16; // 指定前缀长度
    req.ifa.ifa_index = ifindex;
    req.ifa.ifa_flags = IFA_F_PERMANENT;
    req.ifa.ifa_scope = RT_SCOPE_UNIVERSE;
    struct rtattr *rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len));
    rta->rta_type = IFA_LOCAL;
    rta->rta_len = RTA_LENGTH(sizeof(addr));
    memcpy(RTA_DATA(rta), &addr, sizeof(addr));
    req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_LENGTH(sizeof(addr));

    // 发送请求消息
    struct sockaddr_nl dest_addr = {0};
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; // 内核处理
    dest_addr.nl_groups = 0; // 不加入多播组

    struct iovec iov = {&req.nh, req.nh.nlmsg_len};
    struct msghdr msg = {&dest_addr, sizeof(dest_addr), &iov, 1, NULL, 0, 0};
    int ret = sendmsg(fd, &msg, 0);
    if (ret < 0) {
        perror("sendmsg");
        close(fd);
        exit(EXIT_FAILURE);
    }

    close(fd);
    return 0;
}

一、imp2源码 整个源码包含三个文件:imp2_k.c, imp2_u.c和imp2.h. 其中imp2_k.c为内核模块的源代码,imp2_u.c为应用程序,即测试代码,imp2.h为两个源文件都需要引用的头文件。其整体的功能是:注册一种新的netlink协议,并注册一个新的NF hook函数。当有ping包发往当前主机或者经过当前主机转发时,内核向用户发送ping包的源IP和目的IP。各个文件的简单分析见下文。 1. imp2.h 该文件主要是定义了一种新的Netlink协议类型NL_IMP2(31)。新的协议类型的选值不能和当前内核中已经定义的netlink协议类型重复。定义了基于该协议类型的消息类型,内核根据接收到消息的不同类型,进行不同的处理:IMP2_U_PID和IMP2_CLOSE分别为请求和关闭。IMP2_K_MSG代表内核空间发送的消息。 该头文件的源码如下: 2. imp2_k.c 该程序为内核模块程序。其完成的功能如下: (1)创建一种新的Netlink协议NL_IMP2,并注册该协议的回调函数kernel_receive。但用户空间通过建立且协议类型为NL_IMP2的socket套接字并调用sendto,sendmsg函数发送数据时,传送到内核空间的数据由kernel_receive进行处理。该函数主要是记录用户进程的ID,用于随后发送数据的时候指定目的。 (2)在Netfilter的hook点NF_IP_PRE_ROUTING注册hook函数get_icmp,对经过该hook点的ping包进行处理。get_icmp首先判断是否是ping包,如果不是,直接Accept。如果是,则记录该包的源IP和目的IP,然后调用send_to_user,将记录的信息发送给kernel_recieve函数中记录的用户进程ID。 该文件的源码如下: 3. imp2_u.c 该程序为用户空间的测试程序。该程序包括以下功能: (1)生成NL_IMP2协议的socket.然后通过调用sendto发送IMP2_U_PID类型的请求信息给内核。然后等待接受内核发回的信息。记住:仅当有ping包经过内核的NF时,内核才会向用户进程发送信息。 (2)当用户进程通过Ctrl+C来结束该程序时,调用信号处理函数sig_int,向内核发送IMP2_CLOSE的消息,结束socket。 该文件的源码如下: 二、编译和测试 1. 整个源文件编译的Makefile如下: all: gcc -O2 -DMODULE -D__KERNEL__ -W -Wstrict-prototypes -Wmissing-prototypes -isystem /lib/modules/`uname -r`/build/include -c -o imp2_k.o imp2_k.c gcc imp2_u.c -o imp2_u install: insmod imp2_k.o uninstall: rmmod imp2_k clean: rm -f imp2_k.o imp2_u 2. 加载内核模块,并执行测试程序。 #make install #./imp2_u 当没有ping包时,终端一直处于等待输出状态。通过另一台主机(192.168.1.100)向当前主机(192.168.1.101)发送ping包,则终端已经有输出: #./imp2_u [root@localhost imp2]# ./imp2_u src: 192.168.1.100, dest: 192.168.1.101 src: 192.168.1.100, dest: 192.168.1.101 src: 192.168.1.100, dest: 192.168.1.101 src: 192.168.1.100, dest: 192.168.1.101
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值