wlanwatch.c revision 153317
1/*- 2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 3. Neither the names of the above-listed copyright holders nor the names 16 * of any contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * Alternatively, this software may be distributed under the terms of the 20 * GNU General Public License ("GPL") version 2 as published by the Free 21 * Software Foundation. 22 * 23 * NO WARRANTY 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34 * THE POSSIBILITY OF SUCH DAMAGES. 35 * 36 * $FreeBSD: head/tools/tools/net80211/wlanwatch/wlanwatch.c 153317 2005-12-11 23:13:54Z sam $ 37 */ 38 39/* 40 * Monitor 802.11 events using a routing socket. 41 * Code liberaly swiped from route(8). 42 */ 43#include <sys/param.h> 44#include <sys/file.h> 45#include <sys/socket.h> 46#include <sys/ioctl.h> 47#include <sys/sysctl.h> 48#include <sys/types.h> 49 50#include <net/if.h> 51#include <net/route.h> 52#include <net/if_dl.h> 53#include <netinet/in.h> 54#include <netinet/if_ether.h> 55#include <netatalk/at.h> 56#include <net80211/ieee80211_freebsd.h> 57#include <arpa/inet.h> 58#include <netdb.h> 59 60#include <ctype.h> 61#include <err.h> 62#include <errno.h> 63#include <paths.h> 64#include <stdio.h> 65#include <stdlib.h> 66#include <string.h> 67#include <sysexits.h> 68#include <unistd.h> 69#include <ifaddrs.h> 70 71static void print_rtmsg(struct rt_msghdr *rtm, int msglen); 72 73int nflag = 0; 74 75int 76main(int argc, char *argv[]) 77{ 78 int n, s; 79 char msg[2048]; 80 81 s = socket(PF_ROUTE, SOCK_RAW, 0); 82 if (s < 0) 83 err(EX_OSERR, "socket"); 84 for(;;) { 85 n = read(s, msg, 2048); 86 print_rtmsg((struct rt_msghdr *)msg, n); 87 } 88 return 0; 89} 90 91static void 92bprintf(fp, b, s) 93 FILE *fp; 94 int b; 95 u_char *s; 96{ 97 int i; 98 int gotsome = 0; 99 100 if (b == 0) 101 return; 102 while ((i = *s++) != 0) { 103 if (b & (1 << (i-1))) { 104 if (gotsome == 0) 105 i = '<'; 106 else 107 i = ','; 108 (void) putc(i, fp); 109 gotsome = 1; 110 for (; (i = *s) > 32; s++) 111 (void) putc(i, fp); 112 } else 113 while (*s > 32) 114 s++; 115 } 116 if (gotsome) 117 putc('>', fp); 118} 119 120char metricnames[] = 121"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount" 122"\1mtu"; 123char routeflags[] = 124"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT" 125"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016" 126"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE" 127"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST"; 128char ifnetflags[] = 129"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" 130"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" 131"\017LINK2\020MULTICAST"; 132char addrnames[] = 133"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; 134 135const char * 136routename(sa) 137 struct sockaddr *sa; 138{ 139 char *cp; 140 static char line[MAXHOSTNAMELEN + 1]; 141 struct hostent *hp; 142 static char domain[MAXHOSTNAMELEN + 1]; 143 static int first = 1, n; 144 145 if (first) { 146 first = 0; 147 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 148 (cp = strchr(domain, '.'))) { 149 domain[MAXHOSTNAMELEN] = '\0'; 150 (void) strcpy(domain, cp + 1); 151 } else 152 domain[0] = 0; 153 } 154 155 if (sa->sa_len == 0) 156 strcpy(line, "default"); 157 else switch (sa->sa_family) { 158 159 case AF_INET: 160 { struct in_addr in; 161 in = ((struct sockaddr_in *)sa)->sin_addr; 162 163 cp = 0; 164 if (in.s_addr == INADDR_ANY || sa->sa_len < 4) 165 cp = "default"; 166 if (cp == 0 && !nflag) { 167 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 168 AF_INET); 169 if (hp) { 170 if ((cp = strchr(hp->h_name, '.')) && 171 !strcmp(cp + 1, domain)) 172 *cp = 0; 173 cp = hp->h_name; 174 } 175 } 176 if (cp) { 177 strncpy(line, cp, sizeof(line) - 1); 178 line[sizeof(line) - 1] = '\0'; 179 } else 180 (void) sprintf(line, "%s", inet_ntoa(in)); 181 break; 182 } 183 184#ifdef INET6 185 case AF_INET6: 186 { 187 struct sockaddr_in6 sin6; /* use static var for safety */ 188 int niflags = 0; 189#ifdef NI_WITHSCOPEID 190 niflags = NI_WITHSCOPEID; 191#endif 192 193 memset(&sin6, 0, sizeof(sin6)); 194 memcpy(&sin6, sa, sa->sa_len); 195 sin6.sin6_len = sizeof(struct sockaddr_in6); 196 sin6.sin6_family = AF_INET6; 197#ifdef __KAME__ 198 if (sa->sa_len == sizeof(struct sockaddr_in6) && 199 (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || 200 IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && 201 sin6.sin6_scope_id == 0) { 202 sin6.sin6_scope_id = 203 ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); 204 sin6.sin6_addr.s6_addr[2] = 0; 205 sin6.sin6_addr.s6_addr[3] = 0; 206 } 207#endif 208 if (nflag) 209 niflags |= NI_NUMERICHOST; 210 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 211 line, sizeof(line), NULL, 0, niflags) != 0) 212 strncpy(line, "invalid", sizeof(line)); 213 214 return(line); 215 } 216#endif 217 218 case AF_LINK: 219 return (link_ntoa((struct sockaddr_dl *)sa)); 220 221 default: 222 { u_short *s = (u_short *)sa; 223 u_short *slim = s + ((sa->sa_len + 1) >> 1); 224 char *cp = line + sprintf(line, "(%d)", sa->sa_family); 225 char *cpe = line + sizeof(line); 226 227 while (++s < slim && cp < cpe) /* start with sa->sa_data */ 228 if ((n = snprintf(cp, cpe - cp, " %x", *s)) > 0) 229 cp += n; 230 else 231 *cp = '\0'; 232 break; 233 } 234 } 235 return (line); 236} 237 238 239static void 240pmsg_addrs(char *cp, int addrs) 241{ 242 struct sockaddr *sa; 243 int i; 244 245 if (addrs == 0) { 246 (void) putchar('\n'); 247 return; 248 } 249 printf("\nsockaddrs: "); 250 bprintf(stdout, addrs, addrnames); 251 putchar('\n'); 252 for (i = 1; i; i <<= 1) 253 if (i & addrs) { 254 sa = (struct sockaddr *)cp; 255 printf(" %s", routename(sa)); 256 cp += SA_SIZE(sa); 257 } 258 putchar('\n'); 259 fflush(stdout); 260} 261 262static const char * 263ether_sprintf(const uint8_t mac[6]) 264{ 265 static char buf[32]; 266 267 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", 268 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 269 return buf; 270} 271 272static void 273print_rtmsg(struct rt_msghdr *rtm, int msglen) 274{ 275 struct if_msghdr *ifm; 276 struct if_announcemsghdr *ifan; 277 char *state; 278 time_t now = time(NULL); 279 char *cnow = ctime(&now); 280 281 if (rtm->rtm_version != RTM_VERSION) { 282 (void) printf("routing message version %d not understood\n", 283 rtm->rtm_version); 284 return; 285 } 286 switch (rtm->rtm_type) { 287 case RTM_IFINFO: 288 ifm = (struct if_msghdr *)rtm; 289 printf("%.19s RTM_IFINFO: if# %d, ", 290 cnow, ifm->ifm_index); 291 switch (ifm->ifm_data.ifi_link_state) { 292 case LINK_STATE_DOWN: 293 state = "down"; 294 break; 295 case LINK_STATE_UP: 296 state = "up"; 297 break; 298 default: 299 state = "unknown"; 300 break; 301 } 302 printf("link: %s, flags:", state); 303 bprintf(stdout, ifm->ifm_flags, ifnetflags); 304 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs); 305 break; 306 case RTM_IFANNOUNCE: 307 ifan = (struct if_announcemsghdr *)rtm; 308 printf("%.19s RTM_IFANNOUNCE: if# %d, what: ", 309 cnow, ifan->ifan_index); 310 switch (ifan->ifan_what) { 311 case IFAN_ARRIVAL: 312 printf("arrival"); 313 break; 314 case IFAN_DEPARTURE: 315 printf("departure"); 316 break; 317 default: 318 printf("#%d", ifan->ifan_what); 319 break; 320 } 321 printf("\n"); 322 break; 323 case RTM_IEEE80211: 324#define V(type) ((struct type *)(&ifan[1])) 325 ifan = (struct if_announcemsghdr *)rtm; 326 printf("%.19s RTM_IEEE80211: ", cnow); 327 switch (ifan->ifan_what) { 328 case RTM_IEEE80211_ASSOC: 329 printf("associate with %s", 330 ether_sprintf(V(ieee80211_join_event)->iev_addr)); 331 break; 332 case RTM_IEEE80211_REASSOC: 333 printf("reassociate with %s", 334 ether_sprintf(V(ieee80211_join_event)->iev_addr)); 335 break; 336 case RTM_IEEE80211_DISASSOC: 337 printf("disassociate"); 338 break; 339 case RTM_IEEE80211_JOIN: 340 case RTM_IEEE80211_REJOIN: 341 printf("%s station %sjoin", 342 ifan->ifan_what == RTM_IEEE80211_REJOIN ? "re" : "", 343 ether_sprintf(V(ieee80211_join_event)->iev_addr)); 344 break; 345 case RTM_IEEE80211_LEAVE: 346 printf("%s station leave", 347 ether_sprintf(V(ieee80211_leave_event)->iev_addr)); 348 break; 349 case RTM_IEEE80211_SCAN: 350 printf("scan complete"); 351 break; 352 case RTM_IEEE80211_REPLAY: 353 printf("replay failure: src %s " 354 , ether_sprintf(V(ieee80211_replay_event)->iev_src) 355 ); 356 printf("dst %s cipher %u keyix %u keyrsc %llu rsc %llu" 357 , ether_sprintf(V(ieee80211_replay_event)->iev_dst) 358 , V(ieee80211_replay_event)->iev_cipher 359 , V(ieee80211_replay_event)->iev_keyix 360 , V(ieee80211_replay_event)->iev_keyrsc 361 , V(ieee80211_replay_event)->iev_rsc 362 ); 363 break; 364 case RTM_IEEE80211_MICHAEL: 365 printf("michael failure: src %s " 366 , ether_sprintf(V(ieee80211_michael_event)->iev_src) 367 ); 368 printf("dst %s cipher %u keyix %u" 369 , ether_sprintf(V(ieee80211_michael_event)->iev_dst) 370 , V(ieee80211_michael_event)->iev_cipher 371 , V(ieee80211_michael_event)->iev_keyix 372 ); 373 break; 374 default: 375 printf("if# %d, what: #%d", 376 ifan->ifan_index, ifan->ifan_what); 377 break; 378 } 379 printf("\n"); 380 break; 381#undef V 382 } 383} 384