linux查看路由器信息,(19)linux通过netlink查询路由信息

本文档详细介绍了两个C语言程序,用于利用Netlink socket在Linux环境中获取路由信息。程序首先创建并绑定NETLINK_ROUTE套接字,然后发送RTM_GETROUTE请求以获取路由表中的信息。通过解析接收到的数据,提取出网关地址。程序还展示了如何处理Netlink消息,包括错误检查和多路复用组的使用。这些示例对于理解Linux网络编程和路由信息查询非常有帮助。
部署运行你感兴趣的模型镜像

(19)linux通过netlink查询路由信息

注:以下两个程序是网上摘抄的

实例1:

#include

#include

#include

#include

#include

#include

#include

#include

#include

struct req {

struct nlmsghdr nlmsg;

struct rtmsg rtm;

};

struct rtattr* get_gw_attr(struct nlmsghdr *nlmsghdr);

int print_route(struct rtattr *rtp);

int main(void)

{

int fd;

int n;

char *c;

char buff[BUFSIZ];

char str[22];

struct req req;

struct rtattr *rtp;

/*

struct rtattr

{

unsigned shortrta_len;

unsigned shortrta_type;

};

*/

struct nlmsghdr nlmsg, *nlp;

/*由于linux内核的netlink部分总是认为在每个netlink消息体中已

经包含了下面的消息头,所以每个应用程序在发送

netlink消息之前需要提供这个头信息:

struct nlmsghdr

{

__u32 nlmsg_len;Length of message

__u16 nlmsg_type;Message type

__u16 nlmsg_flags; Additional flags

__u32 nlmsg_seq;Sequence number

__u32 nlmsg_pid;Sending process PID

};

*/

struct rtmsg rtm;

/*

struct rtmsg

{

unsigned charrtm_family;

unsigned charrtm_dst_len;

unsigned charrtm_src_len;

unsigned charrtm_tos;

unsigned charrtm_table;Routing table id

unsigned charrtm_protocol;Routing protocol; see below

unsigned charrtm_scope;See below

unsigned charrtm_type;See below

unsignedrtm_flags;

};

*/

struct sockaddr so;

/*

structsockaddr_nl{sa_family_t    nl_family;AF_NETLINKunsignedshortnl_pad;zero__u32          nl_pid;process pid__u32          nl_groups;mcast groups mask}nladdr;

*/

struct sockaddr_nl nl;

struct in_addr addr;

fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

if (fd < 0) {

perror("open error");

exit (1);

}

nl.nl_family = AF_NETLINK;

nl.nl_pad = 0;

nl.nl_pid = getpid();

nl.nl_groups = 0;

n = bind(fd, (struct sockaddr*)&nl, sizeof(nl));

if (n < 0) {

perror(" binderror");

exit (1);

}

memset(&nlmsg, 0, sizeof(struct nlmsghdr));

req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));

req.nlmsg.nlmsg_type = RTM_GETROUTE;

/** In kernel header comments NLM_F_ROOT "specify tree root", but On somebooks

* said this means return the entire table not just one entry **/

req.nlmsg.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;

//req.nlmsg.nlmsg_pid = nl.pid;/** this is not required! **/

memset(&rtm, 0, sizeof(struct rtmsg));

req.rtm.rtm_family = AF_NETLINK;

/** we need change here **/

req.rtm.rtm_dst_len = 4;

req.rtm.rtm_src_len = 4;

req.rtm.rtm_table = RT_TABLE_MAIN;

req.rtm.rtm_protocol = RTPROT_BOOT;/** Route installed during boot **/

req.rtm.rtm_scope = RT_SCOPE_LINK; /** located on directly LAN **/

req.rtm.rtm_type = RTN_UNICAST;/** Gateway or direct route **/

n = send(fd, &req, sizeof(req), 0);

if (n < 0)

{

perror("send error!");

exit (-1);

}

else

printf("%d bytes send!\n",n);

n = recv(fd, buff, BUFSIZ, 0);

if (n < 0)

perror("received failed!");

printf("%d bytes received!\n", n);

for (nlp = (struct nlmsghdr*)buff; \

(nlp->nlmsg_type != NLMSG_DONE)&& NLMSG_OK(nlp, n); nlp = NLMSG_NEXT(nlp, n)) {

rtp = get_gw_attr(nlp);

if (rtp) {

print_route(rtp);

return;

}

}

}

struct rtattr* get_gw_attr(struct nlmsghdr *nlmsghdr)

{

struct rtattr *rta;

int len;

int gw;

char str[16];

len = nlmsghdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));

/** NLMSG_DATA(nlmsghdr) return the rtmsg pointer following, and RTM_RTA return

the rtattr pointer following the rtmsg.**/

rta = RTM_RTA(NLMSG_DATA(nlmsghdr));

while (RTA_OK(rta, len)) {

if (rta->rta_type >= RTA_MAX)

break;

/** We check if the address is INADDR_ANY.I don't know whethher this is needed **/

if(rta->rta_type == RTA_GATEWAY && *(int *)RTA_DATA(rta) != INADDR_ANY)

return rta;

rta = RTA_NEXT(rta, len);

}

return NULL;

};

int print_route(struct rtattr *rtp)

{

char str[16];

char *c;

char buff[16];

c = inet_ntop (AF_INET, RTA_DATA(rtp), buff, INET_ADDRSTRLEN);

if (!c) {

perror("inet_ntop failed !");

exit (1);

}

printf("The gateway IP address is %s\n",c);

}

实例2:

//#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

typedef uint32_t u32;

typedef uint16_t u16;

struct nlsock {

int sock;//套接字描述符

int seq;//包序号

struct sockaddr_nl snl;//netlink地址结构体

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;

//建立NETLINK套接字,并且协议域是NETLINK_ROUTE路由器协议

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;

}

/*struct sockaddr_nl

{

sa_family_tnl_family;// AF_NETLINK//

unsigned short nl_pad;/// zero//

__u32nl_pid;/// process pid //

__u32nl_groups;/// mcast groups mask //

} nladdr;

*/

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;

}

//请求的地址簇,类型

//ret = nl_request ( AF_INET, RTM_GETROUTE, &nl_cmd );

static int nl_request ( int family, int type, struct nlsock *nl )

{

int ret;

struct sockaddr_nl snl;

struct {

struct nlmsghdr nlh;

struct rtgenmsg g;//struct rtgenmsg结构

} req;

/*struct rtgenmsg

{

unsigned charrtgen_family;

};*/

/*由于linux内核的netlink部分总是认为在每个netlink消息体中已

经包含了下面的消息头,所以每个应用程序在发送

netlink消息之前需要提供这个头信息:

struct nlmsghdr

{

__u32 nlmsg_len;Length of message

__u16 nlmsg_type;Message type

__u16 nlmsg_flags; Additional flags

__u32 nlmsg_seq;Sequence number

__u32 nlmsg_pid;Sending process PID

};

*/

/* 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;

}

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值