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