Получение таблицы маршрутизации на MACOSX (программно) - PullRequest
1 голос
/ 22 марта 2011

Вопрос в том, как я могу получить таблицу маршрутизации на MACOSX? Я не имею в виду netstat -nr . Я имею в виду, как сделать это программно, используя C . Первым делом я скачал исходные коды netstat с opensource.apple.com. Я нашел void mroutepr (void) функцию в mroute.c .
Эта функция выглядит как функция, которая получает таблицу маршрутизации, но я не уверен.

Существует объявление массива: 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) * Функция 1034 * является точкой входа для получения таблицы маршрутизации. Затем в функции 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);
    }
}

1 Ответ

1 голос
/ 29 июня 2012

Это в основном то, что вы хотите.Есть еще один механизм, который (лично мне нравится немного больше, чем sysctl - но я думаю, что оба требуют корневого доступа, так что это стирка ... Но, сделав запрос RTM_GET к сокету маршрутизации, вы можете получить ту же информацию. 6 из половиныдюжина и т. д.

#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);
}
...