以下源实现为遍历MAC苹果电脑系统上配置的所有IP路由表配置,回调 predicate 过滤函数只在 AF_INET(IPV4)的时候跳出,其它时不处理,人们可以根据自己的需求改动。
无需依赖MAC OS框架库提供的函数,最小依赖才有可能更容易移植代码到 Apple Inc. 其它操作系统平台上面,另外是 MAC OS 平台依赖不容易受高版本限制。
- static int FetchAllRouteNtreeStuff(const ppp::function<bool(int interface_index, uint32_t ip, uint32_t gw, uint32_t mask)>& predicate) noexcept /* sysctlbyname("net.route.0.0.dump", buf, &len, NULL, 0) */
- {
- if (NULL == predicate)
- {
- return -1;
- }
-
- int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY };
- size_t needed = 0;
- if (sysctl(mib, arraysizeof(mib), NULL, &needed, NULL, 0) < 0)
- {
- return -1;
- }
-
- std::shared_ptr
buffer_managed = ppp::make_shared_alloc(needed); - if (NULL == buffer_managed)
- {
- return -1;
- }
-
- char* buffer = (char*)buffer_managed.get();
- if (sysctl(mib, arraysizeof(mib), buffer, &needed, NULL, 0) < 0)
- {
- return -1;
- }
-
- struct rt_msghdr* rtm = NULL;
- char* buffer_needed = buffer + needed;
-
- for (char* i = buffer; i < buffer_needed; i += rtm->rtm_msglen)
- {
- rtm = (struct rt_msghdr*)(i); /* RTAX_NETMASK */
- if (rtm->rtm_type != RTM_GET)
- {
- continue;
- }
-
- /* inet_ntop(AF_INET, &sa->sin_addr.s_addr, line, sizeof(line) - 1); */
- if (!(rtm->rtm_flags & RTF_UP))
- {
- continue;
- }
-
- /* MAXHOSTNAMELEN; */
- if (!(rtm->rtm_flags & RTF_GATEWAY))
- {
- continue;
- }
-
- struct sockaddr* sa_tab[RTAX_MAX];
- if (struct sockaddr* sa = (struct sockaddr*)(rtm + 1); NULL != sa)
- {
- for (int j = 0; j < RTAX_MAX; j++)
- {
- if (rtm->rtm_addrs & (1 << j))
- {
- sa_tab[j] = sa;
- sa = (struct sockaddr*)((char*)sa + ROUNDUP(sa->sa_len));
- }
- else
- {
- sa_tab[j] = NULL;
- }
- }
- }
-
- uint32_t ip = IPEndPoint::AnyAddress;
- uint32_t gw = IPEndPoint::AnyAddress;
- uint32_t mask = IPEndPoint::AnyAddress;
- if (rtm->rtm_addrs & (1 << RTAX_DST))
- {
- struct sockaddr_in* sa = (struct sockaddr_in*)(sa_tab[RTAX_DST]);
- if (sa->sin_family != AF_INET)
- {
- continue;
- }
-
- ip = sa->sin_addr.s_addr;
- }
-
- if (rtm->rtm_addrs & (1 << RTAX_GATEWAY))
- {
- struct sockaddr_in* sa = (struct sockaddr_in*)(sa_tab[RTAX_GATEWAY]);
- if (sa->sin_family != AF_INET)
- {
- continue;
- }
-
- gw = sa->sin_addr.s_addr;
- }
-
- if (rtm->rtm_addrs & (1 << RTAX_NETMASK))
- {
- struct sockaddr_in* sa = (struct sockaddr_in*)(sa_tab[RTAX_NETMASK]);
- mask = sa->sin_addr.s_addr;
- }
-
- if (predicate(rtm->rtm_index, ip, gw, mask))
- {
- break;
- }
- }
-
- return 0;
- }