Skip to content

Instantly share code, notes, and snippets.

@etodd
Last active October 24, 2024 16:28
Show Gist options
  • Save etodd/d8184b91c02306b889c13eb03f81fb6d to your computer and use it in GitHub Desktop.
Save etodd/d8184b91c02306b889c13eb03f81fb6d to your computer and use it in GitHub Desktop.
dump route table on macos
// stolen from https://stackoverflow.com/a/11265543
#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);
}
free(buf);
}
int
main(int argc __unused, char *argv[] __unused)
{
ntreestuff();
return (0);
}
// stolen from https://stackoverflow.com/a/8095530
#include <stdio.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include "getgateway.h"
#include "route.h"
#include <net/if.h>
#include <string.h>
#define CTL_NET 4 /* network, see socket.h */
#if defined(BSD) || defined(__APPLE__)
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int getdefaultgateway(in_addr_t * addr)
{
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
NET_RT_FLAGS, RTF_GATEWAY};
size_t l;
char * buf, * p;
struct rt_msghdr * rt;
struct sockaddr * sa;
struct sockaddr * sa_tab[RTAX_MAX];
int i;
int r = -1;
if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
return -1;
}
if(l>0) {
buf = malloc(l);
if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
return -1;
}
for(p=buf; p<buf+l; p+=rt->rtm_msglen) {
rt = (struct rt_msghdr *)p;
sa = (struct sockaddr *)(rt + 1);
for(i=0; i<RTAX_MAX; i++) {
if(rt->rtm_addrs & (1 << i)) {
sa_tab[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
sa_tab[i] = NULL;
}
}
if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
&& sa_tab[RTAX_DST]->sa_family == AF_INET
&& sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
char ifName[128];
if_indextoname(rt->rtm_index,ifName);
if(strcmp("en0",ifName)==0){
*addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
r = 0;
}
}
}
}
free(buf);
}
return r;
}
#endif
#include <stdio.h>
#include <stdlib.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 int ntreestuff(void)
{
int mib[6];
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
size_t needed;
if ( sysctl( mib, 6, NULL, &needed, NULL, 0 ) < 0 )
{
return -1;
}
char * buffer;
if ( ( buffer = (char *)( malloc( needed ) ) ) == NULL )
{
return -1;
}
if ( sysctl( mib, 6, buffer, &needed, NULL, 0 ) < 0 )
{
return -1;
}
struct rt_msghdr * rtm;
int count = 0;
for ( char * i = buffer; i < buffer + needed; i += rtm->rtm_msglen )
{
rtm = (struct rt_msghdr *)( i );
if ( rtm->rtm_type != RTM_GET )
continue;
if ( !( rtm->rtm_flags & RTF_UP ) )
continue;
if ( !( rtm->rtm_flags & RTF_GATEWAY ) )
continue;
if ( !( rtm->rtm_addrs & ( 1 << RTAX_DST ) ) )
continue;
if ( !( rtm->rtm_addrs & ( 1 << RTAX_NETMASK ) ) )
continue;
printf( "flags: %x\n", rtm->rtm_flags );
struct sockaddr * sa = (struct sockaddr *)( (char *)( rtm ) + sizeof( struct rt_msghdr ) );
struct sockaddr_in * sockin;
char line[MAXHOSTNAMELEN];
if ( rtm->rtm_addrs & ( 1 << RTAX_DST ) )
{
sockin = (struct sockaddr_in *)( sa + RTAX_DST );
inet_ntop( AF_INET, &sockin->sin_addr.s_addr, line, sizeof( line ) - 1 );
printf( "dest: %s\n", line );
}
if ( rtm->rtm_addrs & ( 1 << RTAX_NETMASK ) )
{
sockin = (struct sockaddr_in *)( sa + RTAX_NETMASK );
inet_ntop( AF_INET, &sockin->sin_addr.s_addr, line, sizeof( line ) - 1 );
printf( "netmask: %s\n", line );
}
if ( rtm->rtm_addrs & ( 1 << RTAX_GATEWAY ) )
{
sockin = (struct sockaddr_in *)( sa + RTAX_GATEWAY );
inet_ntop( AF_INET, &sockin->sin_addr.s_addr, line, sizeof( line ) - 1 );
printf( "gateway: %s\n", line );
}
printf( "iface: %hu\n", rtm->rtm_index );
count++;
}
printf( "count: %d\n", count );
free( buffer );
return 0;
}
int main( int argc, char ** argv )
{
(void) argc;
(void) argv;
ntreestuff();
return 0;
}
@keyallis
Copy link

@Wangzihaooooo 0.0.0.0 is the default value to my understanding. Mac has many network devices these days and not all of them will have a gateway configured. I think it can be assumed that 0.0.0.0 is not a valid gateway address, and if that value is encountered in the sockaddr struct, then it is essentially unset.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment