#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#ifdef __NetBSD__
#include <net80211/ieee80211_netbsd.h>
#elif __FreeBSD__
#include <net80211/ieee80211_freebsd.h>
#else
#error "No support for your operating system!"
#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <inttypes.h>
enum ieee80211_notify_cac_event {
IEEE80211_NOTIFY_CAC_START = 0,
IEEE80211_NOTIFY_CAC_STOP = 1,
IEEE80211_NOTIFY_CAC_RADAR = 2,
IEEE80211_NOTIFY_CAC_EXPIRE = 3,
};
static void print_rtmsg(struct rt_msghdr *rtm, int msglen);
static int nflag = 0;
int
main(int argc, char *argv[])
{
int n, s;
char msg[2048];
(void) argc;
(void) argv;
s = socket(PF_ROUTE, SOCK_RAW, 0);
if (s < 0)
err(EX_OSERR, "socket");
for(;;) {
n = read(s, msg, 2048);
print_rtmsg((struct rt_msghdr *)msg, n);
}
return 0;
}
static void
bprintf(FILE *fp, int b, char *s)
{
int i;
int gotsome = 0;
if (b == 0)
return;
while ((i = *s++) != 0) {
if (b & (1 << (i-1))) {
if (gotsome == 0)
i = '<';
else
i = ',';
(void) putc(i, fp);
gotsome = 1;
for (; (i = *s) > 32; s++)
(void) putc(i, fp);
} else
while (*s > 32)
s++;
}
if (gotsome)
putc('>', fp);
}
static char ifnetflags[] =
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
"\017LINK2\020MULTICAST";
static char addrnames[] =
"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
static char defaultname[] = "default";
#define SOCKADDR_CNV_CONST(sa, sa_fam) \
((struct sa_fam *)(void *) (sa))
static const char *
routename(struct sockaddr *sa)
{
static char line[MAXHOSTNAMELEN + 1];
struct hostent *hp;
static char domain[MAXHOSTNAMELEN + 1];
static int first = 1, n;
if (first) {
char *cp = NULL;
first = 0;
if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
(cp = strchr(domain, '.'))) {
domain[MAXHOSTNAMELEN] = '\0';
(void) strcpy(domain, cp + 1);
} else
domain[0] = 0;
}
if (sa->sa_len == 0)
strcpy(line, "default");
else switch (sa->sa_family) {
case AF_INET:
{ struct in_addr in;
char *cp;
in = SOCKADDR_CNV_CONST(sa, sockaddr_in)->sin_addr;
cp = NULL;
if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
cp = defaultname;
if (cp == NULL && !nflag) {
hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
AF_INET);
if (hp) {
if ((cp = strchr(hp->h_name, '.')) &&
!strcmp(cp + 1, domain))
*cp = 0;
cp = hp->h_name;
}
}
if (cp) {
strncpy(line, cp, sizeof(line) - 1);
line[sizeof(line) - 1] = '\0';
} else
(void) sprintf(line, "%s", inet_ntoa(in));
break;
}
#ifdef INET6
case AF_INET6:
{
struct sockaddr_in6 sin6;
int niflags = 0;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6, sa, sa->sa_len);
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
#ifdef __KAME__
if (sa->sa_len == sizeof(struct sockaddr_in6) &&
(IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
sin6.sin6_scope_id == 0) {
sin6.sin6_scope_id =
ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
sin6.sin6_addr.s6_addr[2] = 0;
sin6.sin6_addr.s6_addr[3] = 0;
}
#endif
if (nflag)
niflags |= NI_NUMERICHOST;
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
line, sizeof(line), NULL, 0, niflags) != 0)
strncpy(line, "invalid", sizeof(line));
return(line);
}
#endif
case AF_LINK:
return (link_ntoa(SOCKADDR_CNV_CONST(sa, sockaddr_dl)));
default:
{ u_short *s = (u_short *)(void *)sa;
u_short *slim = s + ((sa->sa_len + 1) >> 1);
char *cp = line + sprintf(line, "(%d)", sa->sa_family);
char *cpe = line + sizeof(line);
while (++s < slim && cp < cpe)
if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0)
cp += n;
else
*cp = '\0';
break;
}
}
return (line);
}
#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
pmsg_addrs(char *cp, int addrs)
{
struct sockaddr *sa;
int i;
if (addrs == 0) {
(void) putchar('\n');
return;
}
printf("\nsockaddrs: ");
bprintf(stdout, addrs, addrnames);
putchar('\n');
for (i = 1; i; i <<= 1)
if (i & addrs) {
sa = (struct sockaddr *)cp;
printf(" %s", routename(sa));
cp += SA_SIZE(sa);
}
putchar('\n');
}
static const char *
ether_sprintf(const uint8_t mac[6])
{
static char buf[32];
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return buf;
}
static void
print_rtmsg(struct rt_msghdr *rtm, int msglen)
{
struct if_msghdr *ifm;
struct if_announcemsghdr *ifan;
time_t now = time(NULL);
char *cnow = ctime(&now);
(void) msglen;
if (rtm->rtm_version != RTM_VERSION) {
(void) printf("routing message version %d not understood\n",
rtm->rtm_version);
return;
}
switch (rtm->rtm_type) {
case RTM_IFINFO:
ifm = (struct if_msghdr *)rtm;
printf("%.19s RTM_IFINFO: if# %d, ",
cnow, ifm->ifm_index);
switch (ifm->ifm_data.ifi_link_state) {
case LINK_STATE_DOWN:
printf("link: down, flags:");
break;
case LINK_STATE_UP:
printf("link: up, flags:");
break;
default:
printf("link: unknown<%d>, flags:",
ifm->ifm_data.ifi_link_state);
break;
}
bprintf(stdout, ifm->ifm_flags, ifnetflags);
pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
fflush(stdout);
break;
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *)rtm;
printf("%.19s RTM_IFANNOUNCE: if# %d, what: ",
cnow, ifan->ifan_index);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
printf("arrival");
break;
case IFAN_DEPARTURE:
printf("departure");
break;
default:
printf("#%d", ifan->ifan_what);
break;
}
printf("\n");
fflush(stdout);
break;
case RTM_IEEE80211:
#define V(type) ((struct type *)(void *)(&ifan[1]))
ifan = (struct if_announcemsghdr *)rtm;
printf("%.19s RTM_IEEE80211: if# %d, ", cnow, ifan->ifan_index);
switch (ifan->ifan_what) {
case RTM_IEEE80211_ASSOC:
printf("associate with %s",
ether_sprintf(V(ieee80211_join_event)->iev_addr));
break;
case RTM_IEEE80211_REASSOC:
printf("reassociate with %s",
ether_sprintf(V(ieee80211_join_event)->iev_addr));
break;
case RTM_IEEE80211_DISASSOC:
printf("disassociate");
break;
case RTM_IEEE80211_JOIN:
case RTM_IEEE80211_REJOIN:
printf("%s station %sjoin",
ether_sprintf(V(ieee80211_join_event)->iev_addr),
ifan->ifan_what == RTM_IEEE80211_REJOIN ? "re" : ""
);
break;
case RTM_IEEE80211_LEAVE:
printf("%s station leave",
ether_sprintf(V(ieee80211_leave_event)->iev_addr));
break;
case RTM_IEEE80211_SCAN:
printf("scan complete");
break;
case RTM_IEEE80211_REPLAY:
printf("replay failure: src %s "
, ether_sprintf(V(ieee80211_replay_event)->iev_src)
);
printf("dst %s cipher %u keyix %u keyrsc %" PRIu64
" rsc %" PRIu64
, ether_sprintf(V(ieee80211_replay_event)->iev_dst)
, V(ieee80211_replay_event)->iev_cipher
, V(ieee80211_replay_event)->iev_keyix
, V(ieee80211_replay_event)->iev_keyrsc
, V(ieee80211_replay_event)->iev_rsc
);
break;
case RTM_IEEE80211_MICHAEL:
printf("michael failure: src %s "
, ether_sprintf(V(ieee80211_michael_event)->iev_src)
);
printf("dst %s cipher %u keyix %u"
, ether_sprintf(V(ieee80211_michael_event)->iev_dst)
, V(ieee80211_michael_event)->iev_cipher
, V(ieee80211_michael_event)->iev_keyix
);
break;
case RTM_IEEE80211_WDS:
printf("%s wds discovery",
ether_sprintf(V(ieee80211_wds_event)->iev_addr));
break;
case RTM_IEEE80211_CSA:
printf("channel switch announcement: channel %u (%u MHz flags 0x%x) mode %d count %d"
, V(ieee80211_csa_event)->iev_ieee
, V(ieee80211_csa_event)->iev_freq
, V(ieee80211_csa_event)->iev_flags
, V(ieee80211_csa_event)->iev_mode
, V(ieee80211_csa_event)->iev_count
);
break;
case RTM_IEEE80211_CAC:
printf("channel availability check "
"(channel %u, %u MHz flags 0x%x) "
, V(ieee80211_cac_event)->iev_ieee
, V(ieee80211_cac_event)->iev_freq
, V(ieee80211_cac_event)->iev_flags
);
switch (V(ieee80211_cac_event)->iev_type) {
case IEEE80211_NOTIFY_CAC_START:
printf("start timer");
break;
case IEEE80211_NOTIFY_CAC_STOP:
printf("stop timer");
break;
case IEEE80211_NOTIFY_CAC_EXPIRE:
printf("timer expired");
break;
case IEEE80211_NOTIFY_CAC_RADAR:
printf("radar detected");
break;
default:
printf("unknown type %d",
V(ieee80211_cac_event)->iev_type);
break;
}
break;
case RTM_IEEE80211_DEAUTH:
printf("%s wds deauth",
ether_sprintf(V(ieee80211_deauth_event)->iev_addr));
break;
case RTM_IEEE80211_AUTH:
printf("%s node authenticate",
ether_sprintf(V(ieee80211_auth_event)->iev_addr));
break;
case RTM_IEEE80211_COUNTRY:
printf("%s adopt country code '%c%c'",
ether_sprintf(V(ieee80211_country_event)->iev_addr),
V(ieee80211_country_event)->iev_cc[0],
V(ieee80211_country_event)->iev_cc[1]);
break;
case RTM_IEEE80211_RADIO:
printf("radio %s",
V(ieee80211_radio_event)->iev_state ? "ON" : "OFF");
break;
default:
printf("what: #%d", ifan->ifan_what);
break;
}
printf("\n");
fflush(stdout);
break;
#undef V
}
}