1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if defined(DOSCCS) && !defined(lint) 8: char copyright[] = 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: 12: static char sccsid[] = "@(#)route.c 5.6.1 (2.11BSD GTE) 1/1/94"; 13: #endif 14: 15: #include <sys/param.h> 16: #include <sys/socket.h> 17: #include <sys/ioctl.h> 18: #include <sys/mbuf.h> 19: 20: #include <net/route.h> 21: #include <netinet/in.h> 22: #include <netns/ns.h> 23: 24: #include <arpa/inet.h> 25: 26: #include <stdio.h> 27: #include <errno.h> 28: #include <ctype.h> 29: #include <netdb.h> 30: 31: struct rtentry route; 32: int s; 33: int forcehost, forcenet, doflush, nflag; 34: struct sockaddr_in sin = { AF_INET }; 35: struct in_addr inet_makeaddr(); 36: char *malloc(); 37: 38: main(argc, argv) 39: int argc; 40: char *argv[]; 41: { 42: 43: if (argc < 2) 44: printf("usage: route [ -n ] [ -f ] [ cmd [ net | host ] args ]\n"), 45: exit(1); 46: s = socket(AF_INET, SOCK_RAW, 0); 47: if (s < 0) { 48: perror("route: socket"); 49: exit(1); 50: } 51: argc--, argv++; 52: for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) { 53: for (argv[0]++; *argv[0]; argv[0]++) 54: switch (*argv[0]) { 55: case 'f': 56: doflush++; 57: break; 58: case 'n': 59: nflag++; 60: break; 61: } 62: } 63: if (doflush) 64: flushroutes(); 65: if (argc > 0) { 66: if (strcmp(*argv, "add") == 0) 67: newroute(argc, argv); 68: else if (strcmp(*argv, "delete") == 0) 69: newroute(argc, argv); 70: else if (strcmp(*argv, "change") == 0) 71: changeroute(argc-1, argv+1); 72: else 73: printf("%s: huh?\n", *argv); 74: } 75: } 76: 77: /* 78: * Purge all entries in the routing tables not 79: * associated with network interfaces. 80: */ 81: #include <nlist.h> 82: 83: struct nlist nl[] = { 84: #define N_RTHOST 0 85: { "_rthost" }, 86: #define N_RTNET 1 87: { "_rtnet" }, 88: #define N_RTHASHSIZE 2 89: { "_rthashsize" }, 90: "", 91: }; 92: 93: #ifdef pdp11 94: u_int base2_10; 95: struct nlist kl[] = { 96: #define N_NETDATA 0 97: { "_netdata" }, 98: "", 99: }; 100: #endif 101: 102: flushroutes() 103: { 104: struct mbuf mb; 105: register struct rtentry *rt; 106: register struct mbuf *m; 107: struct mbuf **routehash; 108: int rthashsize, i, doinghost = 1, kmem; 109: char *routename(), *netname(); 110: 111: #ifdef pdp11 112: nlist("/unix", kl); 113: if (kl[N_NETDATA].n_value == 0) { 114: printf("route: \"netdata\", symbol not in namelist\n"); 115: exit(1); 116: } 117: nlist("/netnix", nl); 118: #else 119: nlist("/unix", nl); 120: #endif 121: if (nl[N_RTHOST].n_value == 0) { 122: printf("route: \"rthost\", symbol not in namelist\n"); 123: exit(1); 124: } 125: if (nl[N_RTNET].n_value == 0) { 126: printf("route: \"rtnet\", symbol not in namelist\n"); 127: exit(1); 128: } 129: if (nl[N_RTHASHSIZE].n_value == 0) { 130: printf("route: \"rthashsize\", symbol not in namelist\n"); 131: exit(1); 132: } 133: #ifdef pdp11 134: kmem = open("/dev/mem", 0); 135: #else 136: kmem = open("/dev/kmem", 0); 137: #endif 138: if (kmem < 0) { 139: perror("route: /dev/kmem"); 140: exit(1); 141: } 142: #ifdef pdp11 143: lseek(kmem, (off_t)kl[N_NETDATA].n_value, 0); 144: read(kmem, &base2_10, sizeof(base2_10)); 145: lseek(kmem, (off_t)nl[N_RTHASHSIZE].n_value + ctob((long)base2_10), 0); 146: #else 147: lseek(kmem, (off_t)nl[N_RTHASHSIZE].n_value, 0); 148: #endif 149: read(kmem, &rthashsize, sizeof (rthashsize)); 150: routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *)); 151: 152: #ifdef pdp11 153: lseek(kmem, (off_t)nl[N_RTHOST].n_value + ctob((long)base2_10), 0); 154: #else 155: lseek(kmem, (off_t)nl[N_RTHOST].n_value, 0); 156: #endif 157: read(kmem, routehash, rthashsize*sizeof (struct mbuf *)); 158: printf("Flushing routing tables:\n"); 159: again: 160: for (i = 0; i < rthashsize; i++) { 161: if (routehash[i] == 0) 162: continue; 163: m = routehash[i]; 164: while (m) { 165: #ifdef pdp11 166: lseek(kmem, (off_t)m + ctob((long)base2_10), 0); 167: #else 168: lseek(kmem, (off_t)m, 0); 169: #endif 170: read(kmem, &mb, sizeof (mb)); 171: rt = mtod(&mb, struct rtentry *); 172: if (rt->rt_flags & RTF_GATEWAY) { 173: printf("%-20.20s ", doinghost ? 174: routename(&rt->rt_dst) : 175: netname(&rt->rt_dst)); 176: printf("%-20.20s ", routename(&rt->rt_gateway)); 177: if (ioctl(s, SIOCDELRT, (caddr_t)rt) < 0) 178: error("delete"); 179: else 180: printf("done\n"); 181: } 182: m = mb.m_next; 183: } 184: } 185: if (doinghost) { 186: #ifdef pdp11 187: lseek(kmem, (off_t)nl[N_RTNET].n_value+ctob((long)base2_10), 0); 188: #else 189: lseek(kmem, (off_t)nl[N_RTNET].n_value, 0); 190: #endif 191: read(kmem, routehash, rthashsize*sizeof (struct mbuf *)); 192: doinghost = 0; 193: goto again; 194: } 195: close(kmem); 196: free(routehash); 197: } 198: 199: char * 200: routename(sa) 201: struct sockaddr *sa; 202: { 203: register char *cp; 204: static char line[50]; 205: struct hostent *hp; 206: static char domain[MAXHOSTNAMELEN + 1]; 207: static int first = 1; 208: char *index(); 209: char *ns_print(); 210: 211: if (first) { 212: first = 0; 213: if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 214: (cp = index(domain, '.'))) 215: (void) strcpy(domain, cp + 1); 216: else 217: domain[0] = 0; 218: } 219: switch (sa->sa_family) { 220: 221: case AF_INET: 222: { struct in_addr in; 223: in = ((struct sockaddr_in *)sa)->sin_addr; 224: 225: cp = 0; 226: if (in.s_addr == INADDR_ANY) 227: cp = "default"; 228: if (cp == 0 && !nflag) { 229: hp = gethostbyaddr(&in, sizeof (struct in_addr), 230: AF_INET); 231: if (hp) { 232: if ((cp = index(hp->h_name, '.')) && 233: !strcmp(cp + 1, domain)) 234: *cp = 0; 235: cp = hp->h_name; 236: } 237: } 238: if (cp) 239: strcpy(line, cp); 240: else { 241: #ifdef pdp11 242: #define C(x) (((int)(x)) & 0xff) 243: #else 244: #define C(x) ((x) & 0xff) 245: #endif 246: in.s_addr = ntohl(in.s_addr); 247: (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 248: C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 249: } 250: break; 251: } 252: 253: case AF_NS: 254: return (ns_print((struct sockaddr_ns *)sa)); 255: 256: default: 257: { u_short *s = (u_short *)sa->sa_data; 258: 259: (void)sprintf(line, "af %d: %x %x %x %x %x %x %x", 260: sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]); 261: break; 262: } 263: } 264: return (line); 265: } 266: 267: /* 268: * Return the name of the network whose address is given. 269: * The address is assumed to be that of a net or subnet, not a host. 270: */ 271: char * 272: netname(sa) 273: struct sockaddr *sa; 274: { 275: char *cp = 0; 276: static char line[50]; 277: struct netent *np = 0; 278: u_long net, mask; 279: register u_long i; 280: int subnetshift; 281: char *ns_print(); 282: 283: switch (sa->sa_family) { 284: 285: case AF_INET: 286: { struct in_addr in; 287: in = ((struct sockaddr_in *)sa)->sin_addr; 288: 289: i = in.s_addr = ntohl(in.s_addr); 290: if (in.s_addr == 0) 291: cp = "default"; 292: else if (!nflag) { 293: if (IN_CLASSA(i)) { 294: mask = IN_CLASSA_NET; 295: subnetshift = 8; 296: } else if (IN_CLASSB(i)) { 297: mask = IN_CLASSB_NET; 298: subnetshift = 8; 299: } else { 300: mask = IN_CLASSC_NET; 301: subnetshift = 4; 302: } 303: /* 304: * If there are more bits than the standard mask 305: * would suggest, subnets must be in use. 306: * Guess at the subnet mask, assuming reasonable 307: * width subnet fields. 308: */ 309: while (in.s_addr &~ mask) 310: mask = (long)mask >> subnetshift; 311: net = in.s_addr & mask; 312: while ((mask & 1) == 0) { 313: mask >>= 1; 314: net >>= 1; 315: } 316: np = getnetbyaddr(net, AF_INET); 317: if (np) 318: cp = np->n_name; 319: } 320: if (cp) 321: strcpy(line, cp); 322: else if ((in.s_addr & 0xffffff) == 0) 323: (void)sprintf(line, "%u", C(in.s_addr >> 24)); 324: else if ((in.s_addr & 0xffffL) == 0) 325: (void)sprintf(line, "%u.%u", C(in.s_addr >> 24), 326: C(in.s_addr >> 16)); 327: else if ((in.s_addr & 0xff) == 0) 328: (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24), 329: C(in.s_addr >> 16), C(in.s_addr >> 8)); 330: else 331: (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 332: C(in.s_addr >> 16), C(in.s_addr >> 8), 333: C(in.s_addr)); 334: break; 335: } 336: 337: case AF_NS: 338: return (ns_print((struct sockaddr_ns *)sa)); 339: break; 340: 341: default: 342: { u_short *s = (u_short *)sa->sa_data; 343: 344: (void)sprintf(line, "af %d: %x %x %x %x %x %x %x", 345: sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]); 346: break; 347: } 348: } 349: return (line); 350: } 351: 352: newroute(argc, argv) 353: int argc; 354: char *argv[]; 355: { 356: struct sockaddr_in *sin; 357: char *cmd, *dest, *gateway; 358: int ishost, metric = 0, ret, attempts, oerrno; 359: struct hostent *hp; 360: extern int errno; 361: 362: cmd = argv[0]; 363: if ((strcmp(argv[1], "host")) == 0) { 364: forcehost++; 365: argc--, argv++; 366: } else if ((strcmp(argv[1], "net")) == 0) { 367: forcenet++; 368: argc--, argv++; 369: } 370: if (*cmd == 'a') { 371: if (argc != 4) { 372: printf("usage: %s destination gateway metric\n", cmd); 373: printf("(metric of 0 if gateway is this host)\n"); 374: return; 375: } 376: metric = atoi(argv[3]); 377: } else { 378: if (argc < 3) { 379: printf("usage: %s destination gateway\n", cmd); 380: return; 381: } 382: } 383: sin = (struct sockaddr_in *)&route.rt_dst; 384: ishost = getaddr(argv[1], &route.rt_dst, &hp, &dest, forcenet); 385: if (forcehost) 386: ishost = 1; 387: if (forcenet) 388: ishost = 0; 389: sin = (struct sockaddr_in *)&route.rt_gateway; 390: (void) getaddr(argv[2], &route.rt_gateway, &hp, &gateway, 0); 391: route.rt_flags = RTF_UP; 392: if (ishost) 393: route.rt_flags |= RTF_HOST; 394: if (metric > 0) 395: route.rt_flags |= RTF_GATEWAY; 396: for (attempts = 1; ; attempts++) { 397: errno = 0; 398: if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT, 399: (caddr_t)&route)) == 0) 400: break; 401: if (errno != ENETUNREACH && errno != ESRCH) 402: break; 403: if (hp && hp->h_addr_list[1]) { 404: hp->h_addr_list++; 405: bcopy(hp->h_addr_list[0], (caddr_t)&sin->sin_addr, 406: hp->h_length); 407: } else 408: break; 409: } 410: oerrno = errno; 411: printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net", 412: dest, gateway); 413: if (attempts > 1 && ret == 0) 414: printf(" (%s)", 415: inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); 416: if (ret == 0) 417: printf("\n"); 418: else { 419: printf(": "); 420: fflush(stdout); 421: errno = oerrno; 422: error(0); 423: } 424: } 425: 426: changeroute(argc, argv) 427: int argc; 428: char *argv[]; 429: { 430: printf("not supported\n"); 431: } 432: 433: error(cmd) 434: char *cmd; 435: { 436: extern int errno; 437: 438: switch(errno) { 439: case ESRCH: 440: fprintf(stderr, "not in table\n"); 441: break; 442: case EBUSY: 443: fprintf(stderr, "entry in use\n"); 444: break; 445: case ENOBUFS: 446: fprintf(stderr, "routing table overflow\n"); 447: break; 448: default: 449: perror(cmd); 450: } 451: } 452: 453: char * 454: savestr(s) 455: char *s; 456: { 457: char *sav; 458: 459: sav = malloc(strlen(s) + 1); 460: if (sav == NULL) { 461: fprintf("route: out of memory\n"); 462: exit(1); 463: } 464: strcpy(sav, s); 465: return (sav); 466: } 467: 468: /* 469: * Interpret an argument as a network address of some kind, 470: * returning 1 if a host address, 0 if a network address. 471: */ 472: getaddr(s, sin, hpp, name, isnet) 473: char *s; 474: struct sockaddr_in *sin; 475: struct hostent **hpp; 476: char **name; 477: int isnet; 478: { 479: struct hostent *hp; 480: struct netent *np; 481: u_long val; 482: 483: *hpp = 0; 484: if (strcmp(s, "default") == 0) { 485: sin->sin_family = AF_INET; 486: sin->sin_addr = inet_makeaddr(0L, INADDR_ANY); 487: *name = "default"; 488: return(0); 489: } 490: sin->sin_family = AF_INET; 491: if (isnet == 0) { 492: val = inet_addr(s); 493: if (val != -1) { 494: sin->sin_addr.s_addr = val; 495: *name = s; 496: return(inet_lnaof(sin->sin_addr) != INADDR_ANY); 497: } 498: } 499: val = inet_network(s); 500: if (val != -1) { 501: sin->sin_addr = inet_makeaddr(val, INADDR_ANY); 502: *name = s; 503: return(0); 504: } 505: np = getnetbyname(s); 506: if (np) { 507: sin->sin_family = np->n_addrtype; 508: sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 509: *name = savestr(np->n_name); 510: return(0); 511: } 512: hp = gethostbyname(s); 513: if (hp) { 514: *hpp = hp; 515: sin->sin_family = hp->h_addrtype; 516: bcopy(hp->h_addr, &sin->sin_addr, hp->h_length); 517: *name = savestr(hp->h_name); 518: return(1); 519: } 520: fprintf(stderr, "%s: bad value\n", s); 521: exit(1); 522: } 523: 524: short ns_nullh[] = {0,0,0}; 525: short ns_bh[] = {-1,-1,-1}; 526: 527: char * 528: ns_print(sns) 529: struct sockaddr_ns *sns; 530: { 531: struct ns_addr work; 532: union { union ns_net net_e; u_long long_e; } net; 533: u_short port; 534: static char mybuf[50], cport[10], chost[25]; 535: char *host = ""; 536: register char *p; register u_char *q; u_char *q_lim; 537: 538: work = sns->sns_addr; 539: port = ntohs(work.x_port); 540: work.x_port = 0; 541: net.net_e = work.x_net; 542: if (ns_nullhost(work) && net.long_e == 0) { 543: if (port ) { 544: (void)sprintf(mybuf, "*.%xH", port); 545: upHex(mybuf); 546: } else 547: (void)sprintf(mybuf, "*.*"); 548: return (mybuf); 549: } 550: 551: if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 552: host = "any"; 553: } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 554: host = "*"; 555: } else { 556: q = work.x_host.c_host; 557: (void)sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 558: q[0], q[1], q[2], q[3], q[4], q[5]); 559: for (p = chost; *p == '0' && p < chost + 12; p++); 560: host = p; 561: } 562: if (port) 563: (void)sprintf(cport, ".%xH", htons(port)); 564: else 565: *cport = 0; 566: 567: (void)sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 568: upHex(mybuf); 569: return(mybuf); 570: } 571: 572: upHex(p0) 573: char *p0; 574: { 575: register char *p = p0; 576: for (; *p; p++) switch (*p) { 577: 578: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 579: *p += ('A' - 'a'); 580: } 581: }