1 /* $OpenBSD: if.c,v 1.57 2008/03/18 20:03:37 claudio Exp $ */ 2 /* $NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/protosw.h> 36 #include <sys/socket.h> 37 #include <sys/sysctl.h> 38 39 #include <net/if.h> 40 #include <net/if_dl.h> 41 #include <net/if_types.h> 42 #include <net/route.h> 43 #include <netinet/in.h> 44 #include <netinet/in_var.h> 45 #include <netinet/if_ether.h> 46 #include <arpa/inet.h> 47 48 #include <limits.h> 49 #include <signal.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include "netstat.h" 56 57 static void print_addr(struct sockaddr *, struct sockaddr **, struct if_data *); 58 static void sidewaysintpr(u_int); 59 static void catchalarm(int); 60 static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 61 static void fetchifs(void); 62 63 /* 64 * Print a description of the network interfaces. 65 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 66 * which is a TAILQ_HEAD. 67 */ 68 void 69 intpr(int interval) 70 { 71 struct if_msghdr ifm; 72 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 73 char name[IFNAMSIZ + 1]; /* + 1 for the '*' */ 74 char *buf, *next, *lim, *cp; 75 struct rt_msghdr *rtm; 76 struct ifa_msghdr *ifam; 77 struct if_data *ifd; 78 struct sockaddr *sa, *rti_info[RTAX_MAX]; 79 struct sockaddr_dl *sdl; 80 u_int64_t total = 0; 81 size_t len; 82 83 if (interval) { 84 sidewaysintpr((unsigned)interval); 85 return; 86 } 87 88 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 89 err(1, "sysctl"); 90 if ((buf = malloc(len)) == NULL) 91 err(1, NULL); 92 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) 93 err(1, "sysctl"); 94 95 printf("%-7.7s %-5.5s %-11.11s %-17.17s ", 96 "Name", "Mtu", "Network", "Address"); 97 if (bflag) 98 printf("%10.10s %10.10s", "Ibytes", "Obytes"); 99 else 100 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 101 "Ipkts", "Ierrs", "Opkts", "Oerrs", "Colls"); 102 if (tflag) 103 printf(" %s", "Time"); 104 if (dflag) 105 printf(" %s", "Drop"); 106 putchar('\n'); 107 108 lim = buf + len; 109 for (next = buf; next < lim; next += rtm->rtm_msglen) { 110 rtm = (struct rt_msghdr *)next; 111 if (rtm->rtm_version != RTM_VERSION) 112 continue; 113 switch (rtm->rtm_type) { 114 case RTM_IFINFO: 115 total = 0; 116 bcopy(next, &ifm, sizeof ifm); 117 ifd = &ifm.ifm_data; 118 119 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 120 get_rtaddrs(ifm.ifm_addrs, sa, rti_info); 121 122 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 123 if (sdl == NULL || sdl->sdl_family != AF_LINK) 124 continue; 125 bzero(name, sizeof(name)); 126 if (sdl->sdl_nlen >= IFNAMSIZ) 127 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 128 else if (sdl->sdl_nlen > 0) 129 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 130 131 if (interface != 0 && strcmp(name, interface) != 0) 132 continue; 133 134 /* mark inactive interfaces with a '*' */ 135 cp = strchr(name, '\0'); 136 if ((ifm.ifm_flags & IFF_UP) == 0) 137 *cp++ = '*'; 138 *cp = '\0'; 139 140 if (qflag) { 141 total = ifd->ifi_ibytes + ifd->ifi_obytes + 142 ifd->ifi_ipackets + ifd->ifi_ierrors + 143 ifd->ifi_opackets + ifd->ifi_oerrors + 144 ifd->ifi_collisions; 145 if (tflag) 146 total += 0; // XXX ifnet.if_timer; 147 if (dflag) 148 total += 0; // XXX ifnet.if_snd.ifq_drops; 149 if (total == 0) 150 continue; 151 } 152 153 printf("%-7s %-5ld ", name, ifd->ifi_mtu); 154 print_addr(rti_info[RTAX_IFP], rti_info, ifd); 155 break; 156 case RTM_NEWADDR: 157 if (qflag && total == 0) 158 continue; 159 if (interface != 0 && strcmp(name, interface) != 0) 160 continue; 161 162 ifam = (struct ifa_msghdr *)next; 163 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 164 RTA_BRD)) == 0) 165 break; 166 167 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 168 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 169 170 printf("%-7s %-5ld ", name, ifd->ifi_mtu); 171 print_addr(rti_info[RTAX_IFA], rti_info, ifd); 172 break; 173 } 174 } 175 } 176 177 static void 178 print_addr(struct sockaddr *sa, struct sockaddr **rtinfo, struct if_data *ifd) 179 { 180 struct sockaddr_dl *sdl; 181 struct sockaddr_in *sin; 182 struct sockaddr_in6 *sin6; 183 char *cp; 184 int m, n; 185 186 switch (sa->sa_family) { 187 case AF_UNSPEC: 188 printf("%-11.11s ", "none"); 189 printf("%-17.17s ", "none"); 190 break; 191 case AF_INET: 192 sin = (struct sockaddr_in *)sa; 193 cp = netname4(sin->sin_addr.s_addr, 194 ((struct sockaddr_in *)rtinfo[RTAX_NETMASK])->sin_addr.s_addr); 195 if (vflag) 196 n = strlen(cp) < 11 ? 11 : strlen(cp); 197 else 198 n = 11; 199 printf("%-*.*s ", n, n, cp); 200 cp = routename4(sin->sin_addr.s_addr); 201 if (vflag) 202 n = strlen(cp) < 17 ? 17 : strlen(cp); 203 else 204 n = 17; 205 printf("%-*.*s ", n, n, cp); 206 207 #if 0 208 if (aflag) { 209 u_long multiaddr; 210 struct in_multi inm; 211 212 multiaddr = (u_long)LIST_FIRST(&ifaddr.in.ia_multiaddrs); 213 while (multiaddr != 0) { 214 kread(multiaddr, &inm, sizeof inm); 215 printf("\n%25s %-17.17s ", "", 216 routename4(inm.inm_addr.s_addr)); 217 multiaddr = (u_long)LIST_NEXT(&inm, inm_list); 218 } 219 } 220 #endif 221 break; 222 case AF_INET6: 223 sin6 = (struct sockaddr_in6 *)sa; 224 #ifdef __KAME__ 225 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 226 sin6->sin6_scope_id = 227 ntohs(*(u_int16_t *) 228 &sin6->sin6_addr.s6_addr[2]); 229 sin6->sin6_addr.s6_addr[2] = 0; 230 sin6->sin6_addr.s6_addr[3] = 0; 231 } 232 #endif 233 cp = netname6(sin6, 234 (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]); 235 if (vflag) 236 n = strlen(cp) < 11 ? 11 : strlen(cp); 237 else 238 n = 11; 239 printf("%-*.*s ", n, n, cp); 240 cp = routename6(sin6); 241 if (vflag) 242 n = strlen(cp) < 17 ? 17 : strlen(cp); 243 else 244 n = 17; 245 printf("%-*.*s ", n, n, cp); 246 #if 0 247 if (aflag) { 248 u_long multiaddr; 249 struct in6_multi inm; 250 struct sockaddr_in6 m6; 251 252 multiaddr = (u_long)LIST_FIRST(&ifaddr.in6.ia6_multiaddrs); 253 while (multiaddr != 0) { 254 kread(multiaddr, &inm, sizeof inm); 255 memset(&m6, 0, sizeof(m6)); 256 m6.sin6_len = sizeof(struct sockaddr_in6); 257 m6.sin6_family = AF_INET6; 258 m6.sin6_addr = inm.in6m_addr; 259 #ifdef __KAME__ 260 if (IN6_IS_ADDR_MC_LINKLOCAL(&m6.sin6_addr) || 261 IN6_IS_ADDR_MC_INTFACELOCAL(&m6.sin6_addr)) { 262 m6.sin6_scope_id = 263 ntohs(*(u_int16_t *) 264 &m6.sin6_addr.s6_addr[2]); 265 m6.sin6_addr.s6_addr[2] = 0; 266 m6.sin6_addr.s6_addr[3] = 0; 267 } 268 #endif 269 cp = routename6(&m6); 270 if (vflag) 271 n = strlen(cp) < 17 ? 17 : strlen(cp); 272 else 273 n = 17; 274 printf("\n%25s %-*.*s ", "", 275 n, n, cp); 276 multiaddr = (u_long)LIST_NEXT(&inm, in6m_entry); 277 } 278 } 279 #endif 280 break; 281 case AF_APPLETALK: 282 printf("atlk:%-12s",atalk_print(sa,0x10) ); 283 printf("%-12s ",atalk_print(sa,0x0b) ); 284 break; 285 case AF_LINK: 286 sdl = (struct sockaddr_dl *)sa; 287 m = printf("%-11.11s ", "<Link>"); 288 if (sdl->sdl_type == IFT_ETHER || 289 sdl->sdl_type == IFT_CARP || 290 sdl->sdl_type == IFT_FDDI || 291 sdl->sdl_type == IFT_ISO88025) 292 printf("%-17.17s ", 293 ether_ntoa((struct ether_addr *)LLADDR(sdl))); 294 else { 295 cp = (char *)LLADDR(sdl); 296 n = sdl->sdl_alen; 297 goto hexprint; 298 } 299 break; 300 default: 301 m = printf("(%d)", sa->sa_family); 302 for (cp = sa->sa_len + (char *)sa; 303 --cp > sa->sa_data && (*cp == 0);) {} 304 n = cp - sa->sa_data + 1; 305 cp = sa->sa_data; 306 hexprint: 307 while (--n >= 0) 308 m += printf("%x%c", *cp++ & 0xff, 309 n > 0 ? '.' : ' '); 310 m = 30 - m; 311 while (m-- > 0) 312 putchar(' '); 313 break; 314 } 315 if (bflag) 316 printf("%10llu %10llu", 317 ifd->ifi_ibytes, ifd->ifi_obytes); 318 else 319 printf("%8llu %5llu %8llu %5llu %5llu", 320 ifd->ifi_ipackets, ifd->ifi_ierrors, 321 ifd->ifi_opackets, ifd->ifi_oerrors, 322 ifd->ifi_collisions); 323 if (tflag) 324 printf(" %4d", 0 /* XXX ifnet.if_timer */); 325 if (dflag) 326 printf(" %4d", 0 /* XXX ifnet.if_snd.ifq_drops */); 327 putchar('\n'); 328 } 329 330 struct iftot { 331 char ift_name[IFNAMSIZ]; /* interface name */ 332 u_int64_t ift_ip; /* input packets */ 333 u_int64_t ift_ib; /* input bytes */ 334 u_int64_t ift_ie; /* input errors */ 335 u_int64_t ift_op; /* output packets */ 336 u_int64_t ift_ob; /* output bytes */ 337 u_int64_t ift_oe; /* output errors */ 338 u_int64_t ift_co; /* collisions */ 339 u_int64_t ift_dr; /* drops */ 340 } ip_cur, ip_old, sum_cur, sum_old; 341 342 volatile sig_atomic_t signalled; /* set if alarm goes off "early" */ 343 344 /* 345 * Print a running summary of interface statistics. 346 * Repeat display every interval seconds, showing statistics 347 * collected over that interval. Assumes that interval is non-zero. 348 * First line printed at top of screen is always cumulative. 349 */ 350 static void 351 sidewaysintpr(unsigned int interval) 352 { 353 struct ifnet ifnet; 354 sigset_t emptyset; 355 int line; 356 357 fetchifs(); 358 if (ip_cur.ift_name[0] == '\0') { 359 fprintf(stderr, "%s: %s: unknown interface\n", 360 __progname, interface); 361 exit(1); 362 } 363 364 (void)signal(SIGALRM, catchalarm); 365 signalled = 0; 366 (void)alarm(interval); 367 banner: 368 if (bflag) 369 printf("%7.7s in %8.8s %6.6s out %5.5s", 370 ip_cur.ift_name, " ", 371 ip_cur.ift_name, " "); 372 else 373 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 374 ip_cur.ift_name, " ", 375 ip_cur.ift_name, " ", " "); 376 if (dflag) 377 printf(" %5.5s", " "); 378 379 if (bflag) 380 printf(" %7.7s in %8.8s %6.6s out %5.5s", 381 "total", " ", "total", " "); 382 else 383 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 384 "total", " ", "total", " ", " "); 385 if (dflag) 386 printf(" %5.5s", " "); 387 putchar('\n'); 388 if (bflag) 389 printf("%10.10s %8.8s %10.10s %5.5s", 390 "bytes", " ", "bytes", " "); 391 else 392 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 393 "packets", "errs", "packets", "errs", "colls"); 394 if (dflag) 395 printf(" %5.5s", "drops"); 396 397 if (bflag) 398 printf(" %10.10s %8.8s %10.10s %5.5s", 399 "bytes", " ", "bytes", " "); 400 else 401 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 402 "packets", "errs", "packets", "errs", "colls"); 403 if (dflag) 404 printf(" %5.5s", "drops"); 405 putchar('\n'); 406 fflush(stdout); 407 line = 0; 408 bzero(&ip_old, sizeof(ip_old)); 409 bzero(&sum_old, sizeof(sum_old)); 410 loop: 411 bzero(&sum_cur, sizeof(sum_cur)); 412 413 fetchifs(); 414 415 if (bflag) 416 printf("%10llu %8.8s %10llu %5.5s", 417 ip_cur.ift_ib - ip_old.ift_ib, " ", 418 ip_cur.ift_ob - ip_old.ift_ob, " "); 419 else 420 printf("%8llu %5llu %8llu %5llu %5llu", 421 ip_cur.ift_ip - ip_old.ift_ip, 422 ip_cur.ift_ie - ip_old.ift_ie, 423 ip_cur.ift_op - ip_old.ift_op, 424 ip_cur.ift_oe - ip_old.ift_oe, 425 ip_cur.ift_co - ip_old.ift_co); 426 if (dflag) 427 printf(" %5llu", 428 /* XXX ifnet.if_snd.ifq_drops - ip->ift_dr); */ 429 0); 430 431 ip_old = ip_cur; 432 433 if (bflag) 434 printf(" %10llu %8.8s %10llu %5.5s", 435 sum_cur.ift_ib - sum_old.ift_ib, " ", 436 sum_cur.ift_ob - sum_old.ift_ob, " "); 437 else 438 printf(" %8llu %5llu %8llu %5llu %5llu", 439 sum_cur.ift_ip - sum_old.ift_ip, 440 sum_cur.ift_ie - sum_old.ift_ie, 441 sum_cur.ift_op - sum_old.ift_op, 442 sum_cur.ift_oe - sum_old.ift_oe, 443 sum_cur.ift_co - sum_old.ift_co); 444 if (dflag) 445 printf(" %5llu", sum_cur.ift_dr - sum_old.ift_dr); 446 447 sum_old = sum_cur; 448 449 putchar('\n'); 450 fflush(stdout); 451 line++; 452 sigemptyset(&emptyset); 453 if (!signalled) 454 sigsuspend(&emptyset); 455 signalled = 0; 456 (void)alarm(interval); 457 if (line == 21) 458 goto banner; 459 goto loop; 460 /*NOTREACHED*/ 461 } 462 463 /* 464 * Called if an interval expires before sidewaysintpr has completed a loop. 465 * Sets a flag to not wait for the alarm. 466 */ 467 /* ARGSUSED */ 468 static void 469 catchalarm(int signo) 470 { 471 signalled = 1; 472 } 473 474 static void 475 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 476 { 477 int i; 478 479 for (i = 0; i < RTAX_MAX; i++) { 480 if (addrs & (1 << i)) { 481 rti_info[i] = sa; 482 sa = (struct sockaddr *)((char *)(sa) + 483 roundup(sa->sa_len, sizeof(long))); 484 } else 485 rti_info[i] = NULL; 486 } 487 } 488 489 static void 490 fetchifs(void) 491 { 492 struct if_msghdr ifm; 493 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 494 struct rt_msghdr *rtm; 495 struct if_data *ifd; 496 struct sockaddr *sa, *rti_info[RTAX_MAX]; 497 struct sockaddr_dl *sdl; 498 char *buf, *next, *lim; 499 char name[IFNAMSIZ]; 500 size_t len; 501 502 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 503 err(1, "sysctl"); 504 if ((buf = malloc(len)) == NULL) 505 err(1, NULL); 506 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) 507 err(1, "sysctl"); 508 509 lim = buf + len; 510 for (next = buf; next < lim; next += rtm->rtm_msglen) { 511 rtm = (struct rt_msghdr *)next; 512 if (rtm->rtm_version != RTM_VERSION) 513 continue; 514 switch (rtm->rtm_type) { 515 case RTM_IFINFO: 516 bcopy(next, &ifm, sizeof ifm); 517 ifd = &ifm.ifm_data; 518 519 sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); 520 get_rtaddrs(ifm.ifm_addrs, sa, rti_info); 521 522 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 523 if (sdl == NULL || sdl->sdl_family != AF_LINK) 524 continue; 525 bzero(name, sizeof(name)); 526 if (sdl->sdl_nlen >= IFNAMSIZ) 527 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 528 else if (sdl->sdl_nlen > 0) 529 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 530 531 if (interface != 0 && !strcmp(name, interface)) { 532 strlcpy(ip_cur.ift_name, name, 533 sizeof(ip_cur.ift_name)); 534 ip_cur.ift_ip = ifd->ifi_ipackets; 535 ip_cur.ift_ib = ifd->ifi_ibytes; 536 ip_cur.ift_ie = ifd->ifi_ierrors; 537 ip_cur.ift_op = ifd->ifi_opackets; 538 ip_cur.ift_ob = ifd->ifi_obytes; 539 ip_cur.ift_oe = ifd->ifi_oerrors; 540 ip_cur.ift_co = ifd->ifi_collisions; 541 ip_cur.ift_dr = 0; 542 /* XXX ifnet.if_snd.ifq_drops */ 543 } 544 545 sum_cur.ift_ip += ifd->ifi_ipackets; 546 sum_cur.ift_ib += ifd->ifi_ibytes; 547 sum_cur.ift_ie += ifd->ifi_ierrors; 548 sum_cur.ift_op += ifd->ifi_opackets; 549 sum_cur.ift_ob += ifd->ifi_obytes; 550 sum_cur.ift_oe += ifd->ifi_oerrors; 551 sum_cur.ift_co += ifd->ifi_collisions; 552 sum_cur.ift_dr += 0; /* XXX ifnet.if_snd.ifq_drops */ 553 break; 554 } 555 } 556 if (interface == NULL) { 557 strlcpy(ip_cur.ift_name, name, 558 sizeof(ip_cur.ift_name)); 559 ip_cur.ift_ip = ifd->ifi_ipackets; 560 ip_cur.ift_ib = ifd->ifi_ibytes; 561 ip_cur.ift_ie = ifd->ifi_ierrors; 562 ip_cur.ift_op = ifd->ifi_opackets; 563 ip_cur.ift_ob = ifd->ifi_obytes; 564 ip_cur.ift_oe = ifd->ifi_oerrors; 565 ip_cur.ift_co = ifd->ifi_collisions; 566 ip_cur.ift_dr = 0; 567 /* XXX ifnet.if_snd.ifq_drops */ 568 } 569 } 570