improve macOS get default gateway IP
currently, we use a shell command to get the gateway in macOS: https://github.com/seladb/PcapPlusPlus/blob/e48be80c8671ca2018db24947c7d71df9c41b1fd/Pcap%2B%2B/src/PcapLiveDevice.cpp#L1013-L1032
We don't need to use shell script here, we can use normal C API instead.
Hey, I would really like to work on this!
@ADTmux sure, let me know if you encounter any issue.
Hey @tigercosmos, I did experiment with the C API - https://man7.org/linux/man-pages/man3/getifaddrs.3.html , but I found that it does not directly contain the gateway for macOS that I can fetch. Are we thinking about any particular API here? Other methods could include using the routing table or ioctl() system call.
@ADTmux That would be interesting. I tested with getifaddrs on macOS 14 (arm) and it works fine to me. What is your platform? Could you also post the testing code (a runnable minimum code in a single cpp file) here?
@tigercosmos I used this code snippet (https://file.io/sCmaptmi8x5A) in PcapPlusPlus/Examples/Tutorials/Tutorial-LiveTraffic/main.cpp for testing the C library, and tried to print as much info as I can get, and I can see all network interfaces' details except the Default Gateway The platform I used is macOS 13.4 (Intel)
@ADTmux next time you can just copied the code here if it is not large (more than 200 lines).
The file you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netdb.h>
int main() {
struct ifaddrs *ifaddr, *ifa;
int family, s;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
printf("Interface: %s\n", ifa->ifa_name);
printf(" Family: ");
switch (family) {
case AF_INET:
printf("AF_INET (IPv4)\n");
break;
case AF_INET6:
printf("AF_INET6 (IPv6)\n");
break;
default:
printf("Unknown\n");
continue;
}
s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf(" Address: %s\n", host);
if (family == AF_INET) {
struct sockaddr_in *netmask = (struct sockaddr_in *)ifa->ifa_netmask;
if (netmask != NULL) {
s = getnameinfo((struct sockaddr *)netmask, sizeof(struct sockaddr_in),
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf(" Netmask: %s\n", host);
}
}
printf(" Flags: %x\n", ifa->ifa_flags);
}
freeifaddrs(ifaddr);
return 0;
}
I will try to run it later.
@ADTmux Just in case if you don't fully understand the requirement. In the code snip at the beginning of the issue, there is a line:
std::string command = "netstat -nr | grep default | grep " + m_Name;
we parse the result (ifaceInfo) and use the IP to feed to IPv4Address:
m_DefaultGateway = IPv4Address(ifaceInfo);
your mission is to find out the correct ifaceInfo (of course you will need to change the name) by the C API.
Hint: the default route has the destination as 0.0.0.0.
Yes I did get the requirement. Basically if I can obtain the Default Gateway as a string I can pass it to IPv4Address()
FYI, not sure if it helps or not, but you may want to refer to the source code of route, which provides the default route by calling route -n get default
https://opensource.apple.com/source/network_cmds/network_cmds-396.6/route.tproj/route.c.auto.html
regarding your code, obviously using getnameinfo() is not enough, you may need to play around with C structs and C APIs more.
@ADTmux please let me know if you encounter any issue
Hi I'd like to work on this issue. Can you re reassign this issue to me @tigercosmos ?
@zhengfeihe sure, please go ahead.