platform: ubuntu 8.10 server
gcc version: gcc version 4.3.2
#include <linux/types.h> #include <asm/types.h> #include <inttypes.h> #include <sys/file.h> #include <sys/user.h> #include <sys/socket.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <linux/if.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <stdbool.h> #include <errno.h> typedef uint32_t u32; typedef uint16_t u16; struct nlsock { int sock; int seq; struct sockaddr_nl snl; char *name; } nl_cmd = { -1, 0, {0}, "netlink-cmd" }; static int index_oif = 0; struct nl_if_info { u32 addr; char *name; }; static int nl_socket ( struct nlsock *nl, unsigned long groups ) { int ret; struct sockaddr_nl snl; int sock; int namelen; sock = socket ( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); if ( sock < 0 ) { fprintf ( stderr, "Can't open %s socket: %s", nl->name, strerror ( errno ) ); return -1; } ret = fcntl ( sock, F_SETFL, O_NONBLOCK ); if ( ret < 0 ) { fprintf ( stderr, "Can't set %s socket flags: %s", nl->name, strerror ( errno ) ); close ( sock ); return -1; } memset ( &snl, 0, sizeof snl ); snl.nl_family = AF_NETLINK; snl.nl_groups = groups; /* Bind the socket to the netlink structure for anything. */ ret = bind ( sock, ( struct sockaddr * ) &snl, sizeof snl ); if ( ret < 0 ) { fprintf ( stderr, "Can't bind %s socket to group 0x%x: %s", nl->name, snl.nl_groups, strerror ( errno ) ); close ( sock ); return -1; } /* multiple netlink sockets will have different nl_pid */ namelen = sizeof snl; ret = getsockname ( sock, ( struct sockaddr * ) &snl, &namelen ); if ( ret < 0 || namelen != sizeof snl ) { fprintf ( stderr, "Can't get %s socket name: %s", nl->name, strerror ( errno ) ); close ( sock ); return -1; } nl->snl = snl; nl->sock = sock; return ret; } static int nl_request ( int family, int type, struct nlsock *nl ) { int ret; struct sockaddr_nl snl; struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; /* Check netlink socket. */ if ( nl->sock < 0 ) { fprintf ( stderr, "%s socket isn't active.", nl->name ); return -1; } memset ( &snl, 0, sizeof snl ); snl.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof req; req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = ++nl->seq; req.g.rtgen_family = family; ret = sendto ( nl->sock, ( void* ) &req, sizeof req, 0, ( struct sockaddr* ) &snl, sizeof snl ); if ( ret < 0 ) { fprintf ( stderr, "%s sendto failed: %s", nl->name, strerror ( errno ) ); return -1; } return 0; } /* Receive message from netlink interface and pass those information to the given function. */ static int nl_parse_info ( int ( *filter ) ( struct sockaddr_nl *, struct nlmsghdr *, void * ), struct nlsock *nl, void *arg ) { int status; int ret = 0; int error; while ( 1 ) { char buf[4096]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { ( void* ) &snl, sizeof snl, &iov, 1, NULL, 0, 0}; struct nlmsghdr *h; status = recvmsg ( nl->sock, &msg, 0 ); if ( status < 0 ) { if ( errno == EINTR ) continue; if ( errno == EWOULDBLOCK || errno == EAGAIN ) break; fprintf ( stderr, "%s recvmsg overrun", nl->name ); continue; } if ( snl.nl_pid != 0 ) { fprintf ( stderr, "Ignoring non kernel message from pid %u", snl.nl_pid ); continue; } if ( status == 0 ) { fprintf ( stderr, "%s EOF", nl->name ); return -1; } if ( msg.msg_namelen != sizeof snl ) { fprintf ( stderr, "%s sender address length error: length %d", nl->name, msg.msg_namelen ); return -1; } for ( h = ( struct nlmsghdr * ) buf; NLMSG_OK ( h, status ); h = NLMSG_NEXT ( h, status ) ) { /* Finish of reading. */ if ( h->nlmsg_type == NLMSG_DONE ) return ret; /* Error handling. */ if ( h->nlmsg_type == NLMSG_ERROR ) { struct nlmsgerr *err = ( struct nlmsgerr * ) NLMSG_DATA ( h ); /* If the error field is zero, then this is an ACK */ if ( err->error == 0 ) { /* return if not a multipart message, otherwise continue */ if ( ! ( h->nlmsg_flags & NLM_F_MULTI ) ) { return 0; } continue; } if ( h->nlmsg_len < NLMSG_LENGTH ( sizeof ( struct nlmsgerr ) ) ) { fprintf ( stderr, "%s error: message truncated", nl->name ); return -1; } fprintf ( stderr, "%s error: %s, type=%u, seq=%u, pid=%d", nl->name, strerror ( -err->error ), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid ); /* ret = -1; continue; */ return -1; } /* skip unsolicited messages originating from command socket */ if ( nl != &nl_cmd && h->nlmsg_pid == nl_cmd.snl.nl_pid ) { continue; } error = ( *filter ) ( &snl, h, arg ); if ( error < 0 ) { fprintf ( stderr, "%s filter function error/n", nl->name ); ret = error; } } /* After error care. */ if ( msg.msg_flags & MSG_TRUNC ) { fprintf ( stderr, "%s error: message truncated", nl->name ); continue; } if ( status ) { fprintf ( stderr, "%s error: data remnant size %d", nl->name, status ); return -1; } } return ret; } static void nl_parse_rtattr ( struct rtattr **tb, int max, struct rtattr *rta, int len ) { while ( RTA_OK ( rta, len ) ) { if ( rta->rta_type <= max ) tb[rta->rta_type] = rta; rta = RTA_NEXT ( rta,len ); } } static int nl_get_oif ( struct sockaddr_nl *snl, struct nlmsghdr *h, void *arg ) { int len; struct rtmsg *rtm; struct rtattr *tb [RTA_MAX + 1]; u_char flags = 0; char anyaddr[16] = {0}; int index; int table; void *dest; void *gate; rtm = NLMSG_DATA ( h ); if ( h->nlmsg_type != RTM_NEWROUTE ) return 0; if ( rtm->rtm_type != RTN_UNICAST ) return 0; table = rtm->rtm_table; len = h->nlmsg_len - NLMSG_LENGTH ( sizeof ( struct rtmsg ) ); if ( len < 0 ) return -1; memset ( tb, 0, sizeof tb ); nl_parse_rtattr ( tb, RTA_MAX, RTM_RTA ( rtm ), len ); if ( rtm->rtm_flags & RTM_F_CLONED ) return 0; if ( rtm->rtm_protocol == RTPROT_REDIRECT ) return 0; if ( rtm->rtm_protocol == RTPROT_KERNEL ) return 0; if ( rtm->rtm_src_len != 0 ) return 0; // 这里可以对所有路由进行识别 // 取得out interface index if ( tb[RTA_OIF] ) { index = * ( int * ) RTA_DATA ( tb[RTA_OIF] ); } if ( tb[RTA_DST] ) dest = RTA_DATA ( tb[RTA_DST] ); else dest = anyaddr; /* Multipath treatment is needed. */ if ( tb[RTA_GATEWAY] ) gate = RTA_DATA ( tb[RTA_GATEWAY] ); // 判断是否为默认路由 if ( dest == anyaddr && gate ) { if ( arg != NULL ) { * ( int * ) arg = index; return 0; } } return 0; } static int nl_get_if_addr ( struct sockaddr_nl *snl, struct nlmsghdr *h, void *arg ) { int len; struct ifaddrmsg *ifa; struct rtattr *tb [IFA_MAX + 1]; void *addr = NULL; void *broad = NULL; u_char flags = 0; char *label = NULL; u32 ifa_addr, ifa_local; char ifa_label[IFNAMSIZ + 1]; ifa = NLMSG_DATA ( h ); if ( ifa->ifa_family != AF_INET ) return 0; if ( h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR ) return 0; len = h->nlmsg_len - NLMSG_LENGTH ( sizeof ( struct ifaddrmsg ) ); if ( len < 0 ) return -1; memset ( tb, 0, sizeof tb ); nl_parse_rtattr ( tb, IFA_MAX, IFA_RTA ( ifa ), len ); if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; if ( tb[IFA_ADDRESS] ) ifa_addr = *(u32 *) RTA_DATA ( tb[IFA_ADDRESS] ); if ( tb[IFA_LOCAL] ) ifa_local = *(u32 *) RTA_DATA ( tb[IFA_LOCAL] ); if ( tb[IFA_LABEL] ) strncpy( ifa_label, RTA_DATA ( tb[IFA_LABEL] ), IFNAMSIZ ); // 打印所有地址信息 printf( "addr=%08x loal=%08x name=%s/n", ifa_addr, ifa_local, ifa_label ); return 0; } int main() { int ret; char if_name[PAGE_SIZE]; char *p; struct nl_if_info if_info = { -1, "eth0" }; ret = nl_socket ( &nl_cmd, 0 ); if ( ret < 0 ) { return ret; } ret = nl_request ( AF_INET, RTM_GETROUTE, &nl_cmd ); if ( ret < 0 ) { return ret; } ret = nl_parse_info ( nl_get_oif, &nl_cmd, &index_oif ); if ( ret < 0 ) return ret; printf ( "oif=%08x /n", index_oif ); if ( index_oif > 0 ) { p = if_indextoname ( index_oif, if_name ); if ( p ) { printf ( "interface=%s/n", p ); } } ret = nl_request ( AF_INET, RTM_GETADDR, &nl_cmd ); if ( ret < 0 ) return ret; ret = nl_parse_info ( nl_get_if_addr, &nl_cmd, &if_info ); if ( ret < 0 ) return ret; return 0; }
参考:
1> RFC3549 - Linux Netlink as an IP Services Protocol
2> Zebra Source code
3> netlink(7) - Linux man page
您还没有登录,请您登录后再发表评论
重点针对跨三层转发交换路由的情况下,如何通过netlink获取gateway的二层地址,将netlink的使用接口话,C语言编写
要在linux下的程序中获取gateway的IP地址,使用netlink是一种直接、可靠的方法,不需要依赖其它命令,直接从linux内核获取信息,netlink编程的中文资料很少,本文试图用尽可能简单的方式讨论使用netlink获取gataway...
Linux下通过netlink给网卡添加和删除IP地址(keeplaived和ip命令也是通过netlink来添加删除IP的)。纯C代码,gcc可直接编译,测试通过。 netlink添加IP可以让一个网卡拥有多个IP地址(可以通过ip addr命令来查看)...
基于Linux Netlink快速写入路由方法的设计与实现,刘鹏展,李昕,本文介绍了linux中一种用户程序与内核通信的一种方式:netlink,对比了netlink与其他内核通信方式的优点;给出了一种基于netlink通信方式来
通过netlink增加路由条目,测试环境ubuntu 10
用户程序源码 eknetlink.c -内核程序源码 netlink提供了一种很好很强大的的用户与内核之间的通讯机制,本文通过静态的新增一个netlink协议类型,并使用这个新的netlink类型实现用户态和内核态的双向通讯,对linux的...
Linux 用户空间使用Netlink监听uevent,不是原理介绍,而是实战demo
通过netlink检测设备热插拔, gcc -o netlink_test.c netlink编译
netlink提供了一种很好很强大的的用户与内核之间的通讯机制,本文通过静态的新增一个netlink协议类型,并使用这个新的netlink类型实现用户态和内核态的双向通讯,对linux的netlink通讯方式有了一个初步的认识。...
Netlink套接字在Linux系统通信中的应用研究.pdf
参考网络资料,整理出来的使用netlink的说明。用在linux系统下实时获得usb设备的状态的改变。
linux内核态与用户态通信机制-netlink,有实例解析+源码,推荐~
netlink 套接字实现的,例如iprote2网络管理工具,它与内核的交互就全部使用了netlink,著名的内核包过滤框架Netfilter在与用户空间的通读,也在最新版本中改变为netlink,无疑,它将是Linux用户态与内核态交流的...
介绍linux内核中netlink协议族的实现,主要是用户态与内核的通信。
关于网络设备中netlink通信机制详解,主要为代码主题的实现
netlink socket编程why & how netlink socekt是一种...类似于TCP/IP中使用AF_INET地址族一样,netlink socket使用地址族AF_NETLINK。每一个netlink socket在内核头文件include/linux/netlink.h中定义自己的协议类型。
Linux 用户态与内核态的交互 ---netlink篇的源码
本文主要介绍linux中内核态与用户态通信的netlink机制。介绍了netlink的程序流程,特点,和具体实现代码
这个库提供了如下模块:Netlink协议实现(RTNetlink, TaskStats等)rtnl, 网络设置 --- 地址(addresses), 路由(routes), 传输控制(traffic controls)nl80211 --- 无线功能相关的API(开发中)nfnetlink --- netfilter ...
网络链接 软件包netlink提供了对Linux netlink套接字的低级访问。 麻省理工学院许可。 有关netlink的工作方式的更多信息,请查看我关于博客系列。 如有任何疑问或需要指导,请在#networking频道中加入 !稳定性有关...
相关推荐
重点针对跨三层转发交换路由的情况下,如何通过netlink获取gateway的二层地址,将netlink的使用接口话,C语言编写
要在linux下的程序中获取gateway的IP地址,使用netlink是一种直接、可靠的方法,不需要依赖其它命令,直接从linux内核获取信息,netlink编程的中文资料很少,本文试图用尽可能简单的方式讨论使用netlink获取gataway...
Linux下通过netlink给网卡添加和删除IP地址(keeplaived和ip命令也是通过netlink来添加删除IP的)。纯C代码,gcc可直接编译,测试通过。 netlink添加IP可以让一个网卡拥有多个IP地址(可以通过ip addr命令来查看)...
基于Linux Netlink快速写入路由方法的设计与实现,刘鹏展,李昕,本文介绍了linux中一种用户程序与内核通信的一种方式:netlink,对比了netlink与其他内核通信方式的优点;给出了一种基于netlink通信方式来
通过netlink增加路由条目,测试环境ubuntu 10
用户程序源码 eknetlink.c -内核程序源码 netlink提供了一种很好很强大的的用户与内核之间的通讯机制,本文通过静态的新增一个netlink协议类型,并使用这个新的netlink类型实现用户态和内核态的双向通讯,对linux的...
Linux 用户空间使用Netlink监听uevent,不是原理介绍,而是实战demo
通过netlink检测设备热插拔, gcc -o netlink_test.c netlink编译
netlink提供了一种很好很强大的的用户与内核之间的通讯机制,本文通过静态的新增一个netlink协议类型,并使用这个新的netlink类型实现用户态和内核态的双向通讯,对linux的netlink通讯方式有了一个初步的认识。...
Netlink套接字在Linux系统通信中的应用研究.pdf
参考网络资料,整理出来的使用netlink的说明。用在linux系统下实时获得usb设备的状态的改变。
linux内核态与用户态通信机制-netlink,有实例解析+源码,推荐~
netlink 套接字实现的,例如iprote2网络管理工具,它与内核的交互就全部使用了netlink,著名的内核包过滤框架Netfilter在与用户空间的通读,也在最新版本中改变为netlink,无疑,它将是Linux用户态与内核态交流的...
介绍linux内核中netlink协议族的实现,主要是用户态与内核的通信。
关于网络设备中netlink通信机制详解,主要为代码主题的实现
netlink socket编程why & how netlink socekt是一种...类似于TCP/IP中使用AF_INET地址族一样,netlink socket使用地址族AF_NETLINK。每一个netlink socket在内核头文件include/linux/netlink.h中定义自己的协议类型。
Linux 用户态与内核态的交互 ---netlink篇的源码
本文主要介绍linux中内核态与用户态通信的netlink机制。介绍了netlink的程序流程,特点,和具体实现代码
这个库提供了如下模块:Netlink协议实现(RTNetlink, TaskStats等)rtnl, 网络设置 --- 地址(addresses), 路由(routes), 传输控制(traffic controls)nl80211 --- 无线功能相关的API(开发中)nfnetlink --- netfilter ...
网络链接 软件包netlink提供了对Linux netlink套接字的低级访问。 麻省理工学院许可。 有关netlink的工作方式的更多信息,请查看我关于博客系列。 如有任何疑问或需要指导,请在#networking频道中加入 !稳定性有关...