Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2373631
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-04-07 18:43:43

19linux通过netlink查询路由信息

 

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

http://blog.csdn.net/force_eagle/archive/2009/07/07/4326662.aspx

 

 

实例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 short  rta_len;

    unsigned short  rta_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 char       rtm_family;

    unsigned char       rtm_dst_len;

    unsigned char       rtm_src_len;

    unsigned char       rtm_tos;

 

    unsigned char       rtm_table;  Routing table id

    unsigned char       rtm_protocol;   Routing protocol; see below   

    unsigned char       rtm_scope;  See below

    unsigned char       rtm_type;   See below 

 

    unsigned        rtm_flags;

};

*/

    struct sockaddr so;

/*

struct sockaddr_nl
{
  sa_family_t    nl_family
;   AF_NETLINK   
  
unsigned short nl_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(" bind  error");

        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_t    nl_family;  // AF_NETLINK   //

           unsigned short nl_pad;     /// zero        //

           __u32          nl_pid;     /// process pid //

           __u32          nl_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 char            rtgen_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;

}

 

 

阅读(4674) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~