1 /* 2 * PPP Routing related Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $FreeBSD$ 21 * 22 */ 23 24 #include <sys/param.h> 25 #include <sys/socket.h> 26 #include <net/if_types.h> 27 #include <net/route.h> 28 #include <net/if.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 #include <net/if_dl.h> 32 #include <netinet/in_systm.h> 33 #include <netinet/ip.h> 34 #include <sys/un.h> 35 #include <netdb.h> 36 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <sys/sysctl.h> 42 #include <termios.h> 43 44 #include "layer.h" 45 #include "defs.h" 46 #include "command.h" 47 #include "mbuf.h" 48 #include "log.h" 49 #include "iplist.h" 50 #include "timer.h" 51 #include "throughput.h" 52 #include "lqr.h" 53 #include "hdlc.h" 54 #include "fsm.h" 55 #include "lcp.h" 56 #include "ccp.h" 57 #include "link.h" 58 #include "slcompress.h" 59 #include "ipcp.h" 60 #include "filter.h" 61 #include "descriptor.h" 62 #include "mp.h" 63 #ifndef NORADIUS 64 #include "radius.h" 65 #endif 66 #include "bundle.h" 67 #include "route.h" 68 #include "prompt.h" 69 #include "iface.h" 70 71 72 static void 73 p_sockaddr(struct prompt *prompt, struct sockaddr *phost, 74 struct sockaddr *pmask, int width) 75 { 76 char buf[29]; 77 struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 78 struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 79 struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 80 81 if (log_IsKept(LogDEBUG)) { 82 char tmp[50]; 83 84 log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 85 log_Printf(LogDEBUG, " Family %d, len %d\n", 86 (int)phost->sa_family, (int)phost->sa_len); 87 inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 88 log_Printf(LogDEBUG, " Addr %s\n", tmp); 89 if (pmask) { 90 inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 91 log_Printf(LogDEBUG, " Mask %s\n", tmp); 92 } 93 } 94 95 switch (phost->sa_family) { 96 case AF_INET: 97 if (!phost) 98 buf[0] = '\0'; 99 else if (ihost4->sin_addr.s_addr == INADDR_ANY) 100 strcpy(buf, "default"); 101 else if (!pmask) 102 strcpy(buf, inet_ntoa(ihost4->sin_addr)); 103 else { 104 u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 105 u_int32_t tst; 106 int bits; 107 int len; 108 struct sockaddr_in net; 109 110 for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 111 if (msk & tst) 112 break; 113 114 for (tst <<= 1; tst; tst <<= 1) 115 if (!(msk & tst)) 116 break; 117 118 net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 119 strcpy(buf, inet_ntoa(net.sin_addr)); 120 for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 121 if (strcmp(buf + len - 2, ".0")) 122 break; 123 124 if (tst) /* non-contiguous :-( */ 125 sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 126 else 127 sprintf(buf + strlen(buf), "/%d", bits); 128 } 129 break; 130 131 case AF_LINK: 132 if (dl->sdl_nlen) 133 snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 134 else if (dl->sdl_alen) { 135 if (dl->sdl_type == IFT_ETHER) { 136 if (dl->sdl_alen < sizeof buf / 3) { 137 int f; 138 u_char *MAC; 139 140 MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 141 for (f = 0; f < dl->sdl_alen; f++) 142 sprintf(buf+f*3, "%02x:", MAC[f]); 143 buf[f*3-1] = '\0'; 144 } else 145 strcpy(buf, "??:??:??:??:??:??"); 146 } else 147 sprintf(buf, "<IFT type %d>", dl->sdl_type); 148 } else if (dl->sdl_slen) 149 sprintf(buf, "<slen %d?>", dl->sdl_slen); 150 else 151 sprintf(buf, "link#%d", dl->sdl_index); 152 break; 153 154 #ifndef NOINET6 155 case AF_INET6: 156 if (!phost) 157 buf[0] = '\0'; 158 else { 159 const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 160 struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 161 struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 162 int masklen, len; 163 const u_char *c; 164 165 /* XXX: ?????!?!?!!!!! This is horrible ! */ 166 if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 167 IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 168 ihost6->sin6_scope_id = 169 ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 170 *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 171 } 172 173 if (mask6) { 174 const u_char *p, *end; 175 176 p = (const u_char *)&mask6->sin6_addr; 177 end = p + 16; 178 for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 179 masklen += 8; 180 181 if (p < end) { 182 for (c = masks; c < masks + sizeof masks; c++) 183 if (*c == *p) { 184 masklen += c - masks; 185 break; 186 } 187 } 188 } else 189 masklen = 128; 190 191 if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 192 snprintf(buf, sizeof buf, "default"); 193 else { 194 getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 195 NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 196 if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 197 snprintf(buf + len, sizeof buf - len, "/%d", masklen); 198 } 199 } 200 break; 201 #endif 202 203 default: 204 sprintf(buf, "<AF type %d>", phost->sa_family); 205 break; 206 } 207 208 prompt_Printf(prompt, "%-*s ", width-1, buf); 209 } 210 211 static struct bits { 212 u_int32_t b_mask; 213 char b_val; 214 } bits[] = { 215 { RTF_UP, 'U' }, 216 { RTF_GATEWAY, 'G' }, 217 { RTF_HOST, 'H' }, 218 { RTF_REJECT, 'R' }, 219 { RTF_DYNAMIC, 'D' }, 220 { RTF_MODIFIED, 'M' }, 221 { RTF_DONE, 'd' }, 222 { RTF_CLONING, 'C' }, 223 { RTF_XRESOLVE, 'X' }, 224 { RTF_LLINFO, 'L' }, 225 { RTF_STATIC, 'S' }, 226 { RTF_PROTO1, '1' }, 227 { RTF_PROTO2, '2' }, 228 { RTF_BLACKHOLE, 'B' }, 229 #ifdef RTF_WASCLONED 230 { RTF_WASCLONED, 'W' }, 231 #endif 232 #ifdef RTF_PRCLONING 233 { RTF_PRCLONING, 'c' }, 234 #endif 235 #ifdef RTF_PROTO3 236 { RTF_PROTO3, '3' }, 237 #endif 238 #ifdef RTF_BROADCAST 239 { RTF_BROADCAST, 'b' }, 240 #endif 241 { 0, '\0' } 242 }; 243 244 #ifndef RTF_WASCLONED 245 #define RTF_WASCLONED (0) 246 #endif 247 248 static void 249 p_flags(struct prompt *prompt, u_int32_t f, int max) 250 { 251 char name[33], *flags; 252 register struct bits *p = bits; 253 254 if (max > sizeof name - 1) 255 max = sizeof name - 1; 256 257 for (flags = name; p->b_mask && flags - name < max; p++) 258 if (p->b_mask & f) 259 *flags++ = p->b_val; 260 *flags = '\0'; 261 prompt_Printf(prompt, "%-*.*s", max, max, name); 262 } 263 264 const char * 265 Index2Nam(int idx) 266 { 267 /* 268 * XXX: Maybe we should select() on the routing socket so that we can 269 * notice interfaces that come & go (PCCARD support). 270 * Or we could even support a signal that resets these so that 271 * the PCCARD insert/remove events can signal ppp. 272 */ 273 static char **ifs; /* Figure these out once */ 274 static int nifs, debug_done; /* Figure out how many once, and debug once */ 275 276 if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 277 int mib[6], have, had; 278 size_t needed; 279 char *buf, *ptr, *end; 280 struct sockaddr_dl *dl; 281 struct if_msghdr *ifm; 282 283 if (ifs) { 284 free(ifs); 285 ifs = NULL; 286 nifs = 0; 287 } 288 debug_done = 0; 289 290 mib[0] = CTL_NET; 291 mib[1] = PF_ROUTE; 292 mib[2] = 0; 293 mib[3] = 0; 294 mib[4] = NET_RT_IFLIST; 295 mib[5] = 0; 296 297 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 298 log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 299 strerror(errno)); 300 return NumStr(idx, NULL, 0); 301 } 302 if ((buf = malloc(needed)) == NULL) 303 return NumStr(idx, NULL, 0); 304 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 305 free(buf); 306 return NumStr(idx, NULL, 0); 307 } 308 end = buf + needed; 309 310 have = 0; 311 for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 312 ifm = (struct if_msghdr *)ptr; 313 if (ifm->ifm_type != RTM_IFINFO) 314 continue; 315 dl = (struct sockaddr_dl *)(ifm + 1); 316 if (ifm->ifm_index > 0) { 317 if (ifm->ifm_index > have) { 318 char **newifs; 319 320 had = have; 321 have = ifm->ifm_index + 5; 322 if (had) 323 newifs = (char **)realloc(ifs, sizeof(char *) * have); 324 else 325 newifs = (char **)malloc(sizeof(char *) * have); 326 if (!newifs) { 327 log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 328 nifs = 0; 329 if (ifs) { 330 free(ifs); 331 ifs = NULL; 332 } 333 free(buf); 334 return NumStr(idx, NULL, 0); 335 } 336 ifs = newifs; 337 memset(ifs + had, '\0', sizeof(char *) * (have - had)); 338 } 339 if (ifs[ifm->ifm_index-1] == NULL) { 340 ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 341 memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 342 ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 343 if (nifs < ifm->ifm_index) 344 nifs = ifm->ifm_index; 345 } 346 } else if (log_IsKept(LogDEBUG)) 347 log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 348 ifm->ifm_index); 349 } 350 free(buf); 351 } 352 353 if (log_IsKept(LogDEBUG) && !debug_done) { 354 int f; 355 356 log_Printf(LogDEBUG, "Found the following interfaces:\n"); 357 for (f = 0; f < nifs; f++) 358 if (ifs[f] != NULL) 359 log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 360 debug_done = 1; 361 } 362 363 if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 364 return NumStr(idx, NULL, 0); 365 366 return ifs[idx-1]; 367 } 368 369 void 370 route_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 371 { 372 char *wp; 373 int rtax; 374 375 wp = (char *)(rtm + 1); 376 377 for (rtax = 0; rtax < RTAX_MAX; rtax++) 378 if (rtm->rtm_addrs & (1 << rtax)) { 379 sa[rtax] = (struct sockaddr *)wp; 380 wp += ROUNDUP(sa[rtax]->sa_len); 381 } else 382 sa[rtax] = NULL; 383 } 384 385 int 386 route_Show(struct cmdargs const *arg) 387 { 388 struct rt_msghdr *rtm; 389 struct sockaddr *sa[RTAX_MAX]; 390 char *sp, *ep, *cp; 391 size_t needed; 392 int mib[6]; 393 394 mib[0] = CTL_NET; 395 mib[1] = PF_ROUTE; 396 mib[2] = 0; 397 mib[3] = 0; 398 mib[4] = NET_RT_DUMP; 399 mib[5] = 0; 400 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 401 log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 402 return (1); 403 } 404 sp = malloc(needed); 405 if (sp == NULL) 406 return (1); 407 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 408 log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 409 free(sp); 410 return (1); 411 } 412 ep = sp + needed; 413 414 prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 415 "Destination", "Gateway"); 416 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 417 rtm = (struct rt_msghdr *)cp; 418 419 route_ParseHdr(rtm, sa); 420 421 if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 422 p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 423 p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 424 425 p_flags(arg->prompt, rtm->rtm_flags, 6); 426 prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 427 } else 428 prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 429 } 430 free(sp); 431 return 0; 432 } 433 434 /* 435 * Delete routes associated with our interface 436 */ 437 void 438 route_IfDelete(struct bundle *bundle, int all) 439 { 440 struct rt_msghdr *rtm; 441 struct sockaddr *sa[RTAX_MAX]; 442 struct sockaddr_in **in; 443 struct in_addr sa_none; 444 int pass; 445 size_t needed; 446 char *sp, *cp, *ep; 447 int mib[6]; 448 449 log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 450 sa_none.s_addr = INADDR_ANY; 451 in = (struct sockaddr_in **)sa; 452 453 mib[0] = CTL_NET; 454 mib[1] = PF_ROUTE; 455 mib[2] = 0; 456 mib[3] = 0; 457 mib[4] = NET_RT_DUMP; 458 mib[5] = 0; 459 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 460 log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 461 strerror(errno)); 462 return; 463 } 464 465 sp = malloc(needed); 466 if (sp == NULL) 467 return; 468 469 if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 470 log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 471 strerror(errno)); 472 free(sp); 473 return; 474 } 475 ep = sp + needed; 476 477 for (pass = 0; pass < 2; pass++) { 478 /* 479 * We do 2 passes. The first deletes all cloned routes. The second 480 * deletes all non-cloned routes. This is done to avoid 481 * potential errors from trying to delete route X after route Y where 482 * route X was cloned from route Y (and is no longer there 'cos it 483 * may have gone with route Y). 484 */ 485 if (RTF_WASCLONED == 0 && pass == 0) 486 /* So we can't tell ! */ 487 continue; 488 for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 489 rtm = (struct rt_msghdr *)cp; 490 route_ParseHdr(rtm, sa); 491 if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET) { 492 log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 493 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 494 Index2Nam(rtm->rtm_index), rtm->rtm_flags, 495 inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 496 if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 497 (all || (rtm->rtm_flags & RTF_GATEWAY))) { 498 if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 499 sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 500 if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 501 (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 502 log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 503 pass); 504 bundle_SetRoute(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 505 sa_none, sa_none, 0, 0); 506 } else 507 log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 508 } else 509 log_Printf(LogDEBUG, 510 "route_IfDelete: Can't remove routes of %d family !\n", 511 sa[RTAX_GATEWAY]->sa_family); 512 } 513 } 514 } 515 } 516 free(sp); 517 } 518 519 int 520 GetIfIndex(char *name) 521 { 522 int idx; 523 const char *got; 524 525 idx = 1; 526 while (strcmp(got = Index2Nam(idx), "???")) 527 if (!strcmp(got, name)) 528 return idx; 529 else 530 idx++; 531 return -1; 532 } 533 534 void 535 route_Change(struct bundle *bundle, struct sticky_route *r, 536 struct in_addr me, struct in_addr peer, struct in_addr dns[2]) 537 { 538 struct in_addr none, del; 539 540 none.s_addr = INADDR_ANY; 541 for (; r; r = r->next) { 542 if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 543 del.s_addr = r->dst.s_addr & r->mask.s_addr; 544 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 545 r->dst = me; 546 if (r->type & ROUTE_GWHISADDR) 547 r->gw = peer; 548 } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 549 del.s_addr = r->dst.s_addr & r->mask.s_addr; 550 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 551 r->dst = peer; 552 if (r->type & ROUTE_GWHISADDR) 553 r->gw = peer; 554 } else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) { 555 del.s_addr = r->dst.s_addr & r->mask.s_addr; 556 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 557 r->dst = dns[0]; 558 if (r->type & ROUTE_GWHISADDR) 559 r->gw = peer; 560 } else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) { 561 del.s_addr = r->dst.s_addr & r->mask.s_addr; 562 bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1, 0); 563 r->dst = dns[1]; 564 if (r->type & ROUTE_GWHISADDR) 565 r->gw = peer; 566 } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 567 r->gw = peer; 568 bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 569 } 570 } 571 572 void 573 route_Add(struct sticky_route **rp, int type, struct in_addr dst, 574 struct in_addr mask, struct in_addr gw) 575 { 576 struct sticky_route *r; 577 int dsttype = type & ROUTE_DSTANY; 578 579 r = NULL; 580 while (*rp) { 581 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 582 (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 583 /* Oops, we already have this route - unlink it */ 584 free(r); /* impossible really */ 585 r = *rp; 586 *rp = r->next; 587 } else 588 rp = &(*rp)->next; 589 } 590 591 if (!r) 592 r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 593 r->type = type; 594 r->next = NULL; 595 r->dst = dst; 596 r->mask = mask; 597 r->gw = gw; 598 *rp = r; 599 } 600 601 void 602 route_Delete(struct sticky_route **rp, int type, struct in_addr dst) 603 { 604 struct sticky_route *r; 605 int dsttype = type & ROUTE_DSTANY; 606 607 for (; *rp; rp = &(*rp)->next) { 608 if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 609 (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 610 r = *rp; 611 *rp = r->next; 612 free(r); 613 break; 614 } 615 } 616 } 617 618 void 619 route_DeleteAll(struct sticky_route **rp) 620 { 621 struct sticky_route *r, *rn; 622 623 for (r = *rp; r; r = rn) { 624 rn = r->next; 625 free(r); 626 } 627 *rp = NULL; 628 } 629 630 void 631 route_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 632 int indent) 633 { 634 int def; 635 int tlen = strlen(tag); 636 637 if (tlen + 2 > indent) 638 prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 639 else 640 prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 641 642 for (; r; r = r->next) { 643 def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 644 645 prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 646 tlen = 0; 647 if (r->type & ROUTE_DSTMYADDR) 648 prompt_Printf(p, "MYADDR"); 649 else if (r->type & ROUTE_DSTHISADDR) 650 prompt_Printf(p, "HISADDR"); 651 else if (r->type & ROUTE_DSTDNS0) 652 prompt_Printf(p, "DNS0"); 653 else if (r->type & ROUTE_DSTDNS1) 654 prompt_Printf(p, "DNS1"); 655 else if (!def) 656 prompt_Printf(p, "%s", inet_ntoa(r->dst)); 657 658 if (def) 659 prompt_Printf(p, "default "); 660 else 661 prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 662 663 if (r->type & ROUTE_GWHISADDR) 664 prompt_Printf(p, "HISADDR\n"); 665 else 666 prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 667 } 668 } 669