【问题标题】:Getting routing table on MACOSX (programmatically)在 MACOSX 上获取路由表(以编程方式)
【发布时间】:2011-03-22 11:03:25
【问题描述】:

问题是如何在 MACOSX 上获取路由表? 我不是说 netstat -nr。我的意思是如何使用 C 以编程方式进行。 首先,我从 opensource.apple.com 下载了 netstat 源代码。 我在 mroute.c 中找到了 void mroutepr(void) 函数。
这个函数看起来像获取路由表的函数,但我不确定。

有一个数组声明: struct vif viftable[CONFIG_MAXVIFS];

但是当我尝试编译 mroutepr 时,我发现 struct vif 没有在 /usr/include/netinet/ip_mroute.h 中声明 我已经添加了所有必要的包含。我已经检查了七次:))

然后我检查 xnu 内核源代码。 我在 xnu 内核中找到了这个结构,在这个文件中:xnu/bsd/netinet/ip_mroute.h. struct vif有完整的定义。

看来这个结构只能在内核模式下使用。

我很困惑。
如何只为内核代码声明 struct vif? netstat 实用程序如何工作?


以上所有内容都不正确 :))) 解决方案在 route.c 文件中。
ntreestuff(void) 函数是获取路由表的入口点。 然后在 np_rtentry(rtm) 函数中,我们将表格打印到控制台。

static void ntreestuff(void)
{
    size_t needed;
    int mib[6];
    char *buf, *next, *lim;
    struct rt_msghdr2 *rtm;

    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = 0;
    mib[4] = NET_RT_DUMP2;
    mib[5] = 0;

    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 
    {
        err(1, "sysctl: net.route.0.0.dump estimate");
    }

    if ((buf = malloc(needed)) == 0) 
    {
        err(2, "malloc(%lu)", (unsigned long)needed);
    }

    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 
    {
        err(1, "sysctl: net.route.0.0.dump");
    }

    lim  = buf + needed;
    for (next = buf; next < lim; next += rtm->rtm_msglen) 
    {
        rtm = (struct rt_msghdr2 *)next;
        np_rtentry(rtm);
    }
}

【问题讨论】:

    标签: macos routing netstat


    【解决方案1】:

    这基本上可以满足您的需求。还有另一种机制(我个人比 sysctl 更喜欢一点——但我认为两者都需要 root 访问权限,所以这是一种清洗。但是,通过向路由套接字发出 RTM_GET 请求,您可以获得相同的信息。6 of one,half一打等等。

    #include <stdio.h>
    #include <stdlib.h>
    #include <err.h>
    
    #include <sys/param.h>
    #include <sys/sysctl.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <net/route.h>
    
    /* Darwin doesn't define this for some very odd reason */
    #ifndef SA_SIZE
    # define SA_SIZE(sa)                        \
        (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?  \
               sizeof(long)     :               \
               1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
    #endif
    
    
    static void
    ntreestuff(void)
    {
        size_t needed;
        int mib[6];
        char *buf, *next, *lim;
        struct rt_msghdr *rtm;
        struct sockaddr *sa;
        struct sockaddr_in *sockin;
        char line[MAXHOSTNAMELEN];
    
        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
        mib[2] = 0;
        mib[3] = 0;
        mib[4] = NET_RT_DUMP;
        mib[5] = 0;
        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
            err(1, "sysctl: net.route.0.0.dump estimate");
        }
    
        if ((buf = (char *)malloc(needed)) == NULL) {
            errx(2, "malloc(%lu)", (unsigned long)needed);
        }
        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
            err(1, "sysctl: net.route.0.0.dump");
        }
        lim  = buf + needed;
        for (next = buf; next < lim; next += rtm->rtm_msglen) {
            rtm = (struct rt_msghdr *)next;
            sa = (struct sockaddr *)(rtm + 1);
            sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
            sockin = (struct sockaddr_in *)sa;
            inet_ntop(AF_INET, &sockin->sin_addr.s_addr, line, sizeof(line) - 1);
            printf("defaultrouter=%s\n", line);
            break;
        }
    
        free(buf);
    }
    
    int
    main(int argc __unused, char *argv[] __unused)
    {
        ntreestuff();
        return (0);
    }
    

    【讨论】:

    • 需要注意的一件事 - 您需要成为 root 才能执行系统调用或通过路由套接字转储路由表。如果您不是,它不会为您做太多。
    • 谢谢你的例子。有没有办法转储 IPv6 路由表?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 2021-12-12
    • 1970-01-01
    相关资源
    最近更新 更多