1: /* pathalias -- by steve bellovin, as told to peter honeyman */ 2: #ifndef lint 3: static char *sccsid = "@(#)printit.c 9.1 87/10/04"; 4: #endif 5: 6: #include "def.h" 7: 8: /* 9: * print the routes by traversing the shortest path tree in preorder. 10: * use lots of char bufs -- profiling indicates this costs about 5 kbytes 11: */ 12: 13: /* exports */ 14: extern void printit(); 15: 16: /* imports */ 17: extern int Cflag, Vflag, Dflag, Fflag; 18: extern p_node Home; 19: #ifndef TMPFILES 20: #define getnode(x) x 21: #define getlink(y) y 22: #else /*TMPFILES*/ 23: extern node *getnode(); 24: extern link *getlink(); 25: #endif /*TMPFILES*/ 26: extern char *Netchars; 27: extern void die(); 28: 29: /* privates */ 30: static p_link Ancestor; /* for -f option */ 31: STATIC void preorder(), setpath(), printhost(), printdomain(); 32: STATIC char *hostpath(); 33: 34: /* in practice, even the longest paths are < 100 bytes */ 35: #ifndef TMPFILES 36: #define PATHSIZE 512 37: #else /*TMPFILES*/ 38: #define PATHSIZE 172 /* this saves a stack segment, which we use in heap */ 39: #endif /*TMPFILES*/ 40: 41: void 42: printit() 43: { p_link l; 44: char pbuf[PATHSIZE]; 45: 46: /* print home */ 47: if (Cflag) 48: printf("%ld\t", (long) getnode(Home)->n_cost); 49: printf("%s\t%%s\n", getnode(Home)->n_name); 50: 51: strcpy(pbuf, "%s"); 52: for (l = getnode(Home)->n_link; l; l = getlink(l)->l_next) { 53: if (getlink(l)->l_flag & LTREE) { 54: getlink(l)->l_flag &= ~LTREE; 55: Ancestor = l; 56: preorder(l, pbuf); 57: strcpy(pbuf, "%s"); 58: } 59: } 60: fflush(stdout); 61: fflush(stderr); 62: } 63: 64: /* 65: * preorder traversal of shortest path tree. 66: */ 67: STATIC void 68: preorder(l, ppath) 69: register p_link l; 70: char *ppath; 71: { register p_node n; 72: p_node ncp; /* circular copy list */ 73: Cost cost; 74: char npath[PATHSIZE]; 75: short p_dir; /* DIR bits of parent (for nets) */ 76: char p_op; /* net op of parent (for nets) */ 77: 78: setpath(l, ppath, npath); 79: n = getlink(l)->l_to; 80: if (printable(n)) { 81: if (Fflag) 82: cost = getnode(getlink(Ancestor)->l_to)->n_cost; 83: else 84: cost = getnode(n)->n_cost; 85: if (ISADOMAIN(getnode(n))) 86: printdomain(n, npath, cost); 87: else if (!(getnode(n)->n_flag & NNET)) { 88: printhost(n, npath, cost); 89: } 90: getnode(n)->n_flag |= PRINTED; 91: for (ncp = getnode(n)->n_copy; ncp != n; 92: ncp = getnode(ncp)->n_copy) 93: getnode(ncp)->n_flag |= PRINTED; 94: } 95: 96: /* prepare routing bits for domain members */ 97: p_dir = getlink(l)->l_flag & LDIR; 98: p_op = getlink(l)->l_netop; 99: 100: /* recursion */ 101: for (l = getnode(n)->n_link; l; l = getlink(l)->l_next) { 102: if (!(getlink(l)->l_flag & LTREE)) 103: continue; 104: /* network member inherits the routing syntax of its gateway */ 105: if (ISANET(getnode(n))) { 106: getlink(l)->l_flag = (getlink(l)->l_flag & ~LDIR) | p_dir; 107: getlink(l)->l_netop = p_op; 108: } 109: getlink(l)->l_flag &= ~LTREE; 110: preorder(l, npath); 111: } 112: } 113: 114: STATIC int 115: printable(n) 116: register p_node n; 117: { p_node ncp; 118: p_link l; 119: 120: if (getnode(n)->n_flag & PRINTED) 121: return 0; 122: 123: /* is there a cheaper copy? */ 124: for (ncp = getnode(n)->n_copy; n != ncp; ncp = getnode(ncp)->n_copy) { 125: if (!(getnode(ncp)->n_flag & MAPPED)) 126: continue; /* unmapped copy */ 127: 128: if (getnode(n)->n_cost > getnode(ncp)->n_cost) 129: return 0; /* cheaper copy */ 130: 131: if (getnode(n)->n_cost == getnode(ncp)->n_cost 132: && !(getnode(ncp)->n_flag & NTERMINAL)) 133: return 0; /* synthetic copy */ 134: } 135: 136: /* will a domain route suffice? */ 137: if (Dflag && !ISANET(getnode(n)) && ISADOMAIN(getnode(getnode(n)->n_parent))) { 138: /* 139: * are there any interesting links? a link 140: * is interesting if it doesn't point back 141: * to the parent, and is not an alias. 142: */ 143: 144: /* check n */ 145: for (l = getnode(n)->n_link; l; l = getlink(l)->l_next) { 146: if (getlink(l)->l_to == getnode(n)->n_parent) 147: continue; 148: if ((!getlink(l)->l_flag & LALIAS)) 149: return 1; 150: } 151: 152: /* check copies of n */ 153: for (ncp = getnode(n)->n_copy; ncp != n; ncp = getnode(ncp)->n_copy) { 154: for (l = getnode(ncp)->n_link; l; l = getlink(l)->l_next) { 155: if (getlink(l)->l_to == getnode(n)->n_parent) 156: continue; 157: if (!(getlink(l)->l_flag & LALIAS)) 158: return 1; 159: } 160: } 161: 162: /* domain route suffices */ 163: return 0; 164: } 165: return 1; 166: } 167: 168: STATIC void 169: setpath(l, ppath, npath) 170: p_link l; 171: register char *ppath, *npath; 172: { register p_node next; 173: register p_node parent; 174: char netchar; 175: 176: next = getlink(l)->l_to; 177: parent = getnode(next)->n_parent; 178: netchar = NETCHAR(getlink(l)); 179: 180: /* for magic @->% conversion */ 181: if (getnode(parent)->n_flag & ATSIGN) 182: getnode(next)->n_flag |= ATSIGN; 183: 184: /* 185: * i've noticed that distant gateways to domains frequently get 186: * ...!gateway!user@dom.ain wrong. ...!gateway!user%dom.ain 187: * seems to work, so if next is a domain and the parent is 188: * not the local host, force a magic %->@ conversion. in this 189: * context, "parent" is the nearest ancestor that is not a net. 190: */ 191: while (ISANET(getnode(parent))) 192: parent = getnode(parent)->n_parent; 193: if (ISADOMAIN(getnode(next)) && parent != Home) 194: getnode(next)->n_flag |= ATSIGN; 195: 196: /* 197: * special handling for nets (including domains) and aliases. 198: * part of the trick is to treat aliases to domains as 0 cost 199: * links. (the author believes they should be declared as such 200: * in the input, but the world disagrees). 201: */ 202: if (ISANET(getnode(next)) || ((getlink(l)->l_flag & LALIAS) 203: && !ISADOMAIN(getnode(parent)))) { 204: strcpy(npath, ppath); 205: return; 206: } 207: 208: if (netchar == '@') 209: if (getnode(next)->n_flag & ATSIGN) 210: netchar = '%'; /* shazam? shaman? */ 211: else 212: getnode(next)->n_flag |= ATSIGN; 213: 214: /* remainder should be a sprintf -- foo on '%' as an operator */ 215: for ( ; *npath = *ppath; ppath++) { 216: if (*ppath == '%') { 217: switch(ppath[1]) { 218: case 's': 219: ppath++; 220: npath = hostpath(npath, l, netchar); 221: break; 222: 223: case '%': 224: *++npath = *++ppath; 225: npath++; 226: break; 227: 228: default: 229: die("unknown escape in setpath"); 230: break; 231: } 232: } else 233: npath++; 234: } 235: } 236: 237: STATIC char * 238: hostpath(path, l, netchar) 239: register char *path; 240: register p_link l; 241: char netchar; 242: { register p_node prev; 243: 244: prev = getnode(getlink(l)->l_to)->n_parent; 245: if (NETDIR(getlink(l)) == LLEFT) { 246: /* host!%s */ 247: strcpy(path, getnode(getlink(l)->l_to)->n_name); 248: path += strlen(path); 249: while (ISADOMAIN(getnode(prev))) { 250: strcpy(path, getnode(prev)->n_name); 251: path += strlen(path); 252: prev = getnode(prev)->n_parent; 253: } 254: *path++ = netchar; 255: if (netchar == '%') 256: *path++ = '%'; 257: *path++ = '%'; 258: *path++ = 's'; 259: } else { 260: /* %s@host */ 261: *path++ = '%'; 262: *path++ = 's'; 263: *path++ = netchar; 264: if (netchar == '%') 265: *path++ = '%'; 266: strcpy(path, getnode(getlink(l)->l_to)->n_name); 267: path += strlen(path); 268: while (ISADOMAIN(getnode(prev))) { 269: strcpy(path, getnode(prev)->n_name); 270: path += strlen(path); 271: prev = getnode(prev)->n_parent; 272: } 273: } 274: return path; 275: } 276: 277: STATIC void 278: printhost(n, path, cost) 279: register p_node n; 280: char *path; 281: Cost cost; 282: { 283: if (getnode(n)->n_flag & PRINTED) 284: die("printhost called twice"); 285: getnode(n)->n_flag |= PRINTED; 286: /* skip private hosts */ 287: if ((getnode(n)->n_flag & ISPRIVATE) == 0) { 288: if (Cflag) 289: printf("%ld\t", (long) cost); 290: fputs(getnode(n)->n_name, stdout); 291: putchar('\t'); 292: puts(path); 293: } 294: } 295: 296: STATIC void 297: printdomain(n, path, cost) 298: register p_node n; 299: char *path; 300: Cost cost; 301: { p_node p; 302: 303: if (getnode(n)->n_flag & PRINTED) 304: die("printdomain called twice"); 305: getnode(n)->n_flag |= PRINTED; 306: 307: /* 308: * print a route for dom.ain if it is a top-level domain, unless 309: * it is private. 310: * 311: * print a route for sub.dom.ain only if all its ancestor dom.ains 312: * are private and sub.dom.ain is not private. 313: */ 314: if (!ISADOMAIN(getnode(getnode(n)->n_parent))) { 315: /* top-level domain */ 316: if (getnode(n)->n_flag & ISPRIVATE) { 317: vprintf(stderr, "ignoring private top-level domain %s\n", getnode(n)->n_name); 318: return; 319: } 320: } else { 321: /* subdomain */ 322: for (p = getnode(n)->n_parent; ISADOMAIN(getnode(p)); 323: p = getnode(p)->n_parent) 324: if (!(getnode(p)->n_flag & ISPRIVATE)) 325: return; 326: if (getnode(n)->n_flag & ISPRIVATE) 327: return; 328: } 329: 330: /* print it (at last!) */ 331: if (Cflag) 332: printf("%ld\t", (long) cost); 333: do { 334: fputs(getnode(n)->n_name, stdout); 335: n = getnode(n)->n_parent; 336: } while (ISADOMAIN(getnode(n))); 337: putchar('\t'); 338: puts(path); 339: }