1 /* $NetBSD: route.c,v 1.22 1997/04/10 15:45:58 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "from: @(#)route.c 8.3 (Berkeley) 3/9/94"; 39 #else 40 static char *rcsid = "$NetBSD: route.c,v 1.22 1997/04/10 15:45:58 christos Exp $"; 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/protosw.h> 46 #include <sys/socket.h> 47 #include <sys/mbuf.h> 48 49 #include <net/if.h> 50 #include <net/if_dl.h> 51 #include <net/if_types.h> 52 #define _KERNEL 53 #include <net/route.h> 54 #undef _KERNEL 55 #include <netinet/in.h> 56 #include <netatalk/at.h> 57 58 #include <netns/ns.h> 59 60 #include <sys/sysctl.h> 61 62 #include <netdb.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include "netstat.h" 68 69 #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) 70 71 /* 72 * Definitions for showing gateway flags. 73 */ 74 struct bits { 75 short b_mask; 76 char b_val; 77 } bits[] = { 78 { RTF_UP, 'U' }, 79 { RTF_GATEWAY, 'G' }, 80 { RTF_HOST, 'H' }, 81 { RTF_REJECT, 'R' }, 82 { RTF_DYNAMIC, 'D' }, 83 { RTF_MODIFIED, 'M' }, 84 { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ 85 { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */ 86 { RTF_CLONING, 'C' }, 87 { RTF_XRESOLVE, 'X' }, 88 { RTF_LLINFO, 'L' }, 89 { RTF_STATIC, 'S' }, 90 { RTF_PROTO1, '1' }, 91 { RTF_PROTO2, '2' }, 92 { 0 } 93 }; 94 95 static union { 96 struct sockaddr u_sa; 97 u_short u_data[128]; 98 } pt_u; 99 100 int do_rtent = 0; 101 struct rtentry rtentry; 102 struct radix_node rnode; 103 struct radix_mask rmask; 104 105 int NewTree = 0; 106 107 static struct sockaddr *kgetsa __P((struct sockaddr *)); 108 static void p_tree __P((struct radix_node *)); 109 static void p_rtnode __P((void)); 110 static void ntreestuff __P((void)); 111 static void np_rtentry __P((struct rt_msghdr *)); 112 static void p_sockaddr __P((const struct sockaddr *, 113 const struct sockaddr *, int, int)); 114 static void p_flags __P((int, char *)); 115 static void p_rtentry __P((struct rtentry *)); 116 static void ntreestuff __P((void)); 117 static u_long forgemask __P((u_long)); 118 static void domask __P((char *, u_long, u_long)); 119 120 /* 121 * Print routing tables. 122 */ 123 void 124 routepr(rtree) 125 u_long rtree; 126 { 127 struct radix_node_head *rnh, head; 128 int i; 129 130 printf("Routing tables\n"); 131 132 if (Aflag == 0 && NewTree) 133 ntreestuff(); 134 else { 135 if (rtree == 0) { 136 printf("rt_tables: symbol not in namelist\n"); 137 return; 138 } 139 140 kget(rtree, rt_tables); 141 for (i = 0; i <= AF_MAX; i++) { 142 if ((rnh = rt_tables[i]) == 0) 143 continue; 144 kget(rnh, head); 145 if (i == AF_UNSPEC) { 146 if (Aflag && af == 0) { 147 printf("Netmasks:\n"); 148 p_tree(head.rnh_treetop); 149 } 150 } else if (af == AF_UNSPEC || af == i) { 151 pr_family(i); 152 do_rtent = 1; 153 pr_rthdr(); 154 p_tree(head.rnh_treetop); 155 } 156 } 157 } 158 } 159 160 /* 161 * Print address family header before a section of the routing table. 162 */ 163 void 164 pr_family(af) 165 int af; 166 { 167 char *afname; 168 169 switch (af) { 170 case AF_INET: 171 afname = "Internet"; 172 break; 173 case AF_NS: 174 afname = "XNS"; 175 break; 176 case AF_ISO: 177 afname = "ISO"; 178 break; 179 case AF_APPLETALK: 180 afname = "AppleTalk"; 181 break; 182 case AF_CCITT: 183 afname = "X.25"; 184 break; 185 default: 186 afname = NULL; 187 break; 188 } 189 if (afname) 190 printf("\n%s:\n", afname); 191 else 192 printf("\nProtocol Family %d:\n", af); 193 } 194 195 /* column widths; each followed by one space */ 196 #define WID_DST 18 /* width of destination column */ 197 #define WID_GW 18 /* width of gateway column */ 198 199 /* 200 * Print header for routing table columns. 201 */ 202 void 203 pr_rthdr() 204 { 205 206 if (Aflag) 207 printf("%-8.8s ","Address"); 208 printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %6.6s %s\n", 209 WID_DST, WID_DST, "Destination", 210 WID_GW, WID_GW, "Gateway", 211 "Flags", "Refs", "Use", "Mtu", "Interface"); 212 } 213 214 static struct sockaddr * 215 kgetsa(dst) 216 register struct sockaddr *dst; 217 { 218 219 kget(dst, pt_u.u_sa); 220 if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 221 kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); 222 return (&pt_u.u_sa); 223 } 224 225 static void 226 p_tree(rn) 227 struct radix_node *rn; 228 { 229 230 again: 231 kget(rn, rnode); 232 if (rnode.rn_b < 0) { 233 if (Aflag) 234 printf("%-8.8lx ", (u_long) rn); 235 if (rnode.rn_flags & RNF_ROOT) { 236 if (Aflag) 237 printf("(root node)%s", 238 rnode.rn_dupedkey ? " =>\n" : "\n"); 239 } else if (do_rtent) { 240 kget(rn, rtentry); 241 p_rtentry(&rtentry); 242 if (Aflag) 243 p_rtnode(); 244 } else { 245 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), 246 NULL, 0, 44); 247 putchar('\n'); 248 } 249 if ((rn = rnode.rn_dupedkey) != NULL) 250 goto again; 251 } else { 252 if (Aflag && do_rtent) { 253 printf("%-8.8lx ", (u_long) rn); 254 p_rtnode(); 255 } 256 rn = rnode.rn_r; 257 p_tree(rnode.rn_l); 258 p_tree(rn); 259 } 260 } 261 262 char nbuf[20]; 263 264 static void 265 p_rtnode() 266 { 267 struct radix_mask *rm = rnode.rn_mklist; 268 269 if (rnode.rn_b < 0) { 270 if (rnode.rn_mask) { 271 printf("\t mask "); 272 p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), 273 NULL, 0, -1); 274 } else if (rm == 0) 275 return; 276 } else { 277 sprintf(nbuf, "(%d)", rnode.rn_b); 278 printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long) rnode.rn_l, 279 (u_long) rnode.rn_r); 280 } 281 while (rm) { 282 kget(rm, rmask); 283 sprintf(nbuf, " %d refs, ", rmask.rm_refs); 284 printf(" mk = %8.8lx {(%d),%s", (u_long) rm, 285 -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); 286 if (rmask.rm_flags & RNF_NORMAL) { 287 struct radix_node rnode_aux; 288 printf(" <normal>, "); 289 kget(rmask.rm_leaf, rnode_aux); 290 p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), 291 NULL, 0, -1); 292 } else 293 p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 294 NULL, 0, -1); 295 putchar('}'); 296 if ((rm = rmask.rm_mklist) != NULL) 297 printf(" ->"); 298 } 299 putchar('\n'); 300 } 301 302 static void 303 ntreestuff() 304 { 305 size_t needed; 306 int mib[6]; 307 char *buf, *next, *lim; 308 register struct rt_msghdr *rtm; 309 310 mib[0] = CTL_NET; 311 mib[1] = PF_ROUTE; 312 mib[2] = 0; 313 mib[3] = 0; 314 mib[4] = NET_RT_DUMP; 315 mib[5] = 0; 316 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 317 { perror("route-sysctl-estimate"); exit(1);} 318 if ((buf = malloc(needed)) == 0) 319 { printf("out of space\n"); exit(1);} 320 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 321 { perror("sysctl of routing table"); exit(1);} 322 lim = buf + needed; 323 for (next = buf; next < lim; next += rtm->rtm_msglen) { 324 rtm = (struct rt_msghdr *)next; 325 np_rtentry(rtm); 326 } 327 } 328 329 static void 330 np_rtentry(rtm) 331 register struct rt_msghdr *rtm; 332 { 333 register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 334 #ifdef notdef 335 static int masks_done, banner_printed; 336 #endif 337 static int old_af; 338 int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 339 340 #ifdef notdef 341 /* for the moment, netmasks are skipped over */ 342 if (!banner_printed) { 343 printf("Netmasks:\n"); 344 banner_printed = 1; 345 } 346 if (masks_done == 0) { 347 if (rtm->rtm_addrs != RTA_DST ) { 348 masks_done = 1; 349 af = sa->sa_family; 350 } 351 } else 352 #endif 353 af = sa->sa_family; 354 if (af != old_af) { 355 pr_family(af); 356 old_af = af; 357 } 358 if (rtm->rtm_addrs == RTA_DST) 359 p_sockaddr(sa, NULL, 0, 36); 360 else { 361 p_sockaddr(sa, NULL, rtm->rtm_flags, 16); 362 if (sa->sa_len == 0) 363 sa->sa_len = sizeof(long); 364 sa = (struct sockaddr *)(sa->sa_len + (char *)sa); 365 p_sockaddr(sa, NULL, 0, 18); 366 } 367 p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 368 putchar('\n'); 369 } 370 371 static void 372 p_sockaddr(sa, mask, flags, width) 373 const struct sockaddr *sa, *mask; 374 int flags, width; 375 { 376 char workbuf[128], *cplim; 377 register char *cp = workbuf; 378 379 switch(sa->sa_family) { 380 case AF_INET: 381 { 382 register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 383 384 if (sin->sin_addr.s_addr == INADDR_ANY) 385 cp = "default"; 386 else if (flags & RTF_HOST) 387 cp = routename(sin->sin_addr.s_addr); 388 else if (mask) 389 cp = netname(sin->sin_addr.s_addr, 390 ((struct sockaddr_in *)mask)->sin_addr.s_addr); 391 else 392 cp = netname(sin->sin_addr.s_addr, INADDR_ANY); 393 break; 394 } 395 396 case AF_APPLETALK: 397 case 0: 398 { 399 if (!(flags & RTF_HOST) && mask) 400 cp = atalk_print2(sa,mask,11); 401 else 402 cp = atalk_print(sa,11); 403 break; 404 } 405 case AF_NS: 406 cp = ns_print((struct sockaddr *)sa); 407 break; 408 409 case AF_LINK: 410 { 411 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 412 413 if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 414 sdl->sdl_slen == 0) 415 (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 416 else switch (sdl->sdl_type) { 417 case IFT_FDDI: 418 case IFT_ETHER: 419 { 420 register int i; 421 register u_char *lla = (u_char *)sdl->sdl_data + 422 sdl->sdl_nlen; 423 424 cplim = ""; 425 for (i = 0; i < sdl->sdl_alen; i++, lla++) { 426 cp += sprintf(cp, "%s%02x", cplim, *lla); 427 cplim = ":"; 428 } 429 cp = workbuf; 430 break; 431 } 432 default: 433 cp = link_ntoa(sdl); 434 break; 435 } 436 break; 437 } 438 439 default: 440 { 441 register u_char *s = (u_char *)sa->sa_data, *slim; 442 443 slim = sa->sa_len + (u_char *) sa; 444 cplim = cp + sizeof(workbuf) - 6; 445 cp += sprintf(cp, "(%d)", sa->sa_family); 446 while (s < slim && cp < cplim) { 447 cp += sprintf(cp, " %02x", *s++); 448 if (s < slim) 449 cp += sprintf(cp, "%02x", *s++); 450 } 451 cp = workbuf; 452 } 453 } 454 if (width < 0 ) 455 printf("%s ", cp); 456 else { 457 if (nflag) 458 printf("%-*s ", width, cp); 459 else 460 printf("%-*.*s ", width, width, cp); 461 } 462 } 463 464 static void 465 p_flags(f, format) 466 register int f; 467 char *format; 468 { 469 char name[33], *flags; 470 register struct bits *p = bits; 471 472 for (flags = name; p->b_mask; p++) 473 if (p->b_mask & f) 474 *flags++ = p->b_val; 475 *flags = '\0'; 476 printf(format, name); 477 } 478 479 static void 480 p_rtentry(rt) 481 register struct rtentry *rt; 482 { 483 static struct ifnet ifnet, *lastif; 484 struct sockaddr *sa, addr, mask; 485 486 if (!(sa = kgetsa(rt_key(rt)))) 487 bzero(&addr, sizeof addr); 488 else 489 addr = *sa; 490 if (!rt_mask(rt) || !(sa = kgetsa(rt_mask(rt)))) 491 bzero(&mask, sizeof mask); 492 else 493 mask = *sa; 494 p_sockaddr(&addr, &mask, rt->rt_flags, WID_DST); 495 p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW); 496 p_flags(rt->rt_flags, "%-6.6s "); 497 printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use); 498 if (rt->rt_rmx.rmx_mtu) 499 printf("%6ld ", rt->rt_rmx.rmx_mtu); 500 else 501 printf("%6s ", "-"); 502 if (rt->rt_ifp) { 503 if (rt->rt_ifp != lastif) { 504 kget(rt->rt_ifp, ifnet); 505 lastif = rt->rt_ifp; 506 } 507 printf(" %.16s%s", ifnet.if_xname, 508 rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); 509 } 510 putchar('\n'); 511 } 512 513 char * 514 routename(in) 515 u_int32_t in; 516 { 517 register char *cp; 518 static char line[MAXHOSTNAMELEN + 1]; 519 struct hostent *hp; 520 static char domain[MAXHOSTNAMELEN + 1]; 521 static int first = 1; 522 523 if (first) { 524 first = 0; 525 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 526 (cp = index(domain, '.'))) 527 (void) strcpy(domain, cp + 1); 528 else 529 domain[0] = 0; 530 } 531 cp = 0; 532 if (!nflag) { 533 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 534 AF_INET); 535 if (hp) { 536 if ((cp = index(hp->h_name, '.')) && 537 !strcmp(cp + 1, domain)) 538 *cp = 0; 539 cp = hp->h_name; 540 } 541 } 542 if (cp) 543 strncpy(line, cp, sizeof(line) - 1); 544 else { 545 #define C(x) ((x) & 0xff) 546 in = ntohl(in); 547 sprintf(line, "%u.%u.%u.%u", 548 C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 549 } 550 return (line); 551 } 552 553 static u_long 554 forgemask(a) 555 u_long a; 556 { 557 u_long m; 558 559 if (IN_CLASSA(a)) 560 m = IN_CLASSA_NET; 561 else if (IN_CLASSB(a)) 562 m = IN_CLASSB_NET; 563 else 564 m = IN_CLASSC_NET; 565 return (m); 566 } 567 568 static void 569 domask(dst, addr, mask) 570 char *dst; 571 u_long addr, mask; 572 { 573 register int b, i; 574 575 if (!mask || (forgemask(addr) == mask)) { 576 *dst = '\0'; 577 return; 578 } 579 i = 0; 580 for (b = 0; b < 32; b++) 581 if (mask & (1 << b)) { 582 register int bb; 583 584 i = b; 585 for (bb = b+1; bb < 32; bb++) 586 if (!(mask & (1 << bb))) { 587 i = -1; /* noncontig */ 588 break; 589 } 590 break; 591 } 592 if (i == -1) 593 sprintf(dst, "&0x%lx", mask); 594 else 595 sprintf(dst, "/%d", 32-i); 596 } 597 598 /* 599 * Return the name of the network whose address is given. 600 * The address is assumed to be that of a net or subnet, not a host. 601 */ 602 char * 603 netname(in, mask) 604 u_int32_t in, mask; 605 { 606 char *cp = 0; 607 static char line[MAXHOSTNAMELEN + 4]; 608 struct netent *np = 0; 609 u_int32_t net, omask; 610 register u_int32_t i; 611 int subnetshift; 612 613 i = ntohl(in); 614 omask = mask = ntohl(mask); 615 if (!nflag && i != INADDR_ANY) { 616 if (mask == INADDR_ANY) { 617 switch (mask = forgemask(i)) { 618 case IN_CLASSA_NET: 619 subnetshift = 8; 620 break; 621 case IN_CLASSB_NET: 622 subnetshift = 8; 623 break; 624 case IN_CLASSC_NET: 625 subnetshift = 4; 626 break; 627 default: 628 abort(); 629 } 630 /* 631 * If there are more bits than the standard mask 632 * would suggest, subnets must be in use. 633 * Guess at the subnet mask, assuming reasonable 634 * width subnet fields. 635 */ 636 while (i &~ mask) 637 mask = (long)mask >> subnetshift; 638 } 639 net = i & mask; 640 while ((mask & 1) == 0) 641 mask >>= 1, net >>= 1; 642 np = getnetbyaddr(net, AF_INET); 643 if (np) 644 cp = np->n_name; 645 } 646 if (cp) 647 strncpy(line, cp, sizeof(line) - 1); 648 else if ((i & 0xffffff) == 0) 649 sprintf(line, "%u", C(i >> 24)); 650 else if ((i & 0xffff) == 0) 651 sprintf(line, "%u.%u", C(i >> 24) , C(i >> 16)); 652 else if ((i & 0xff) == 0) 653 sprintf(line, "%u.%u.%u", C(i >> 24), C(i >> 16), C(i >> 8)); 654 else 655 sprintf(line, "%u.%u.%u.%u", C(i >> 24), 656 C(i >> 16), C(i >> 8), C(i)); 657 domask(line+strlen(line), i, omask); 658 return (line); 659 } 660 661 /* 662 * Print routing statistics 663 */ 664 void 665 rt_stats(off) 666 u_long off; 667 { 668 struct rtstat rtstat; 669 670 if (off == 0) { 671 printf("rtstat: symbol not in namelist\n"); 672 return; 673 } 674 kread(off, (char *)&rtstat, sizeof (rtstat)); 675 printf("routing:\n"); 676 printf("\t%u bad routing redirect%s\n", 677 rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); 678 printf("\t%u dynamically created route%s\n", 679 rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); 680 printf("\t%u new gateway%s due to redirects\n", 681 rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); 682 printf("\t%u destination%s found unreachable\n", 683 rtstat.rts_unreach, plural(rtstat.rts_unreach)); 684 printf("\t%u use%s of a wildcard route\n", 685 rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); 686 } 687 short ns_nullh[] = {0,0,0}; 688 short ns_bh[] = {-1,-1,-1}; 689 690 char * 691 ns_print(sa) 692 struct sockaddr *sa; 693 { 694 register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 695 struct ns_addr work; 696 union { union ns_net net_e; u_long long_e; } net; 697 u_short port; 698 static char mybuf[50], cport[10], chost[25]; 699 char *host = ""; 700 register char *p; register u_char *q; 701 702 work = sns->sns_addr; 703 port = ntohs(work.x_port); 704 work.x_port = 0; 705 net.net_e = work.x_net; 706 if (ns_nullhost(work) && net.long_e == 0) { 707 if (port ) { 708 sprintf(mybuf, "*.%xH", port); 709 upHex(mybuf); 710 } else 711 sprintf(mybuf, "*.*"); 712 return (mybuf); 713 } 714 715 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 716 host = "any"; 717 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 718 host = "*"; 719 } else { 720 q = work.x_host.c_host; 721 sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 722 q[0], q[1], q[2], q[3], q[4], q[5]); 723 for (p = chost; *p == '0' && p < chost + 12; p++) 724 continue; 725 host = p; 726 } 727 if (port) 728 sprintf(cport, ".%xH", htons(port)); 729 else 730 *cport = 0; 731 732 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 733 upHex(mybuf); 734 return(mybuf); 735 } 736 737 char * 738 ns_phost(sa) 739 struct sockaddr *sa; 740 { 741 register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 742 struct sockaddr_ns work; 743 static union ns_net ns_zeronet; 744 char *p; 745 746 work = *sns; 747 work.sns_addr.x_port = 0; 748 work.sns_addr.x_net = ns_zeronet; 749 750 p = ns_print((struct sockaddr *)&work); 751 if (strncmp("0H.", p, 3) == 0) p += 3; 752 return(p); 753 } 754 755 void 756 upHex(p0) 757 char *p0; 758 { 759 register char *p = p0; 760 for (; *p; p++) switch (*p) { 761 762 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 763 *p += ('A' - 'a'); 764 } 765 } 766