|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T U
Length: 123665 (0x1e311) Types: TextFile Notes: Uncompressed file
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦11cb2e5aa⟧ »EurOpenD3/mail/pathalias.shar.Z« └─⟦this⟧
# To unbundle, sh this file echo README 1>&2 sed 's/^-//' >README <<'//GO.SYSIN DD README' -From citi!honey Sun Oct 4 23:30 EDT 1987 -Date: 04 Oct 1987 23:30 EDT -From: honey@citi.umich.edu -To: whom it may concern -Subject: pathalias compilation instructions - -edit config.h -make - -if getopt is undefined, obtain a copy from usenet group -comp.sources.unix and adjust Makefile. - -pathalias input is regularly published in usenet group comp.mail.maps. - - peter - -ps: pathalias, written by steve bellovin and peter honeyman, is in the - public domain, and may be used by any person or organization, in - any way and for any purpose. - -pps: There is no warranty of merchantability nor any warranty of fit- - ness for a particular purpose nor any other warranty, either ex- - press or implied, as to the accuracy of the enclosed materials or - as to their suitability for any particular purpose. Accordingly, - the authors assume no responsibility for their use by the recipi- - ent. Further, the authors assume no obligation to furnish any - assistance of any kind whatsoever, or to furnish any additional - information or documentation. This paragraph was copied without - permission from an old crypt(1) man page. //GO.SYSIN DD README echo CHANGES 1>&2 sed 's/^-//' >CHANGES <<'//GO.SYSIN DD CHANGES' -Nets without names. -Allow negative cost components; prohibit negative costs. -New input syntax: adjust {host, ...}; kill -a option. -New input syntax: file {filename}. -New input syntax: delete {host, host!neighbor}. -Terminal nets. -Prevent back links to domains. - --- mod.sources, 10/87 -- version 9 -Terminal edges and domains (<host> syntax and -D option). -Dead hosts and edges in the input stream. -Empty private list ends scope of privates. -First hop cost in output (-f option). -Penalize deprecated hosts (-a option). - --- mod.sources, 4.3bsd, 1/86 -- version 8 -Improved alias treatment. -Routes to domain gateways. -Leading dot in name implies domain. -Link/host tracing (-t option). -Use getopt(). - --- mod.sources, 8/85 -- version 7 -Private hosts documented. -Homegrown scanner -- it was true what they said about lex. -Makedb. -Domains and gateways. -DEAD back link. - --- net.sources, 1/85 -- version 6 -No ! in dbm key. -Network character must be one of !@%: -- dot is dead. -Private hosts. -Discourage hybrid addresses. -Magic @ <-> % rule. - --- 1983-1984 -- version 5 -Reverse sense of the -c (cost) flag. -Use cheapest among duplicate links. -Elide network names in output. - --- epoch (smb version) -- versions 1-4 //GO.SYSIN DD CHANGES echo pathalias.8 1>&2 sed 's/^-//' >pathalias.8 <<'//GO.SYSIN DD pathalias.8' -.\" @(#)pathalias.8 9.5 88/05/10 -.TH PATHALIAS 8 "5/10/88" "Public Domain" -.SH NAME -pathalias, makedb, arpatxt \- mail routing tools -.SH SYNOPSIS -.B pathalias -[ -.B \-ivcDf -] [ -.BI \-t \0link -] [ -.BI \-l \0host -] [ -.BI \-d \0link -] [ -.ig -.\" for pathparse. -.BI \-g \0file -] [ -.. -.I files ... -] -.PP -.B makedb -[ -.B \-a -] [ -.BI \-o \0dbmfile -] [ -.I files ... -] -.PP -.B arpatxt -[ -.B \-@fi -] [ -.BI \-g \0gateway -] [ -.BI \-p \0privatefile -] [ -.BI \-d \0directory -] [ -.I files ... -] -.ad b -.SH DESCRIPTION -.I Pathalias -computes the shortest paths and corresponding routes from one host -(computer system) to all other known, reachable hosts. -.I Pathalias -reads host-to-host connectivity -information on standard input or in the named -.IR files , -and writes a list of -host-route pairs on the standard output. -.PP -Here are the -.I pathalias -options: -.TP 6 -.B \-i -Ignore case: map all host names to lower case. -By default, case is significant. -.TP -.B \-c -Print costs: print the path cost before each host-route pair. -.TP -.B \-v -Verbose: report some statistics on the standard error output. -.TP -.B \-D -Terminal domains: see -.I domains -section. -.TP -.B \-f -First hop cost: the printed cost is the cost to the first relay in a path, -instead of the cost of the path itself; implies (and overrides) the -.B \-c -option. -.ig -.\" the -g option is for pathparse and is not for public consumption (yet!). -.TP -.BI \-g \0file -Dump the edges of the graph into the named file. -.. -.TP -.BI \-l \0host -Set local host name to -.IR host . -By default, -.I pathalias -discovers the local host name in a system-dependent way. -.TP -.BI \-d \0arg -Declare a dead link, host, or network. -If -.I arg -is of the form ``host-1!host-2,'' the link from host-1 to host-2 -is treated as an extremely high cost (\fIi.e.\fP, \s-1DEAD\s0) link. -If -.I arg -is a single host name, -that host is treated as dead -and is used as a relay host of last resort on any path. -If -.I arg -is a network name, the network requires a gateway. -.TP -.BI \-t \0arg -Trace input for link, host or network on the standard error output. -The form of -.I arg -is as above. -.PP -.I Makedb -takes -.I pathalias -output and creates or appends to a -.IR dbm (3) -database. -.PP -Here are the -.I makedb -options: -.TP 6 -.B \-a -Append to an existing database; -by default, -.I makedb -truncates the database. -.TP -.BI \-o \0dbmfile -Identify the output file base name. -.PP -.I Arpatxt -converts the Internet hosts table -.I hosts.txt -into -.I pathalias -input. -.PP -Here are the -.I arpatxt -options: -.TP 6 -.B \-@ -Generate -.I pathalias -input that specifies `@' style addressing. The default -is to produce -.I pathalias -input that specifies `!' style addressing. -.TP -.B \-f -\&``Filter mode'' \(em write output on stdout. Normally, -.I arpatxt -writes the description of each domain into a separate file. -.TP -.B \-i -Map output to lower case. -.TP -.BI \-g \0arg -Declare a gateway to the Internet or one of its subdomains. If -.I arg -contains one or more dots, the left-hand side component that contains -no dots is declared a gateway to the domain to the right of the dot. -Otherwise, -.I arg -is declared a gateway to the Internet as a whole. -.TP -.BI \-p \0privatefile -.I Privatefile -contains a list of host names that conflict with other names. -.TP -.BI \-d \0directory -Write output files in -.IR directory . -.SS \fIPathalias\fP Input Format -A line beginning with white space continues the preceding line. -Anything following `#' on an input line is ignored. -.PP -A list of host-to-host connections consists of a ``from'' host in column 1, -followed by white space, -followed by a comma-separated list of ``to' hosts, called -.IR links . -A link may be preceded or followed by a network character to use -in the route. -Valid network characters are `!' (default), `@', `:', and `%'. -A link (and network character, if present) may be -followed by a ``cost'' enclosed in parentheses. -Costs may be arbitrary -arithmetic expressions involving numbers, parentheses, `+', `\-', `*', -and `/'. -Negative costs are prohibited. -The following symbolic costs are -recognized: -.PP -.RS -.nf -.ta 14mR 17m -\s-1LOCAL\s0 25 (local-area network connection) -\s-1DEDICATED\s0 95 (high speed dedicated link) -\s-1DIRECT\s0 200 (toll-free call) -\s-1DEMAND\s0 300 (long-distance call) -\s-1HOURLY\s0 500 (hourly poll) -\s-1EVENING\s0 1800 (time restricted call) -\s-1DAILY\s0 5000 (daily poll, also called \s-1POLLED\s0) -\s-1WEEKLY\s0 30000 (irregular poll) -.fi -.RE -.PP -In addition, -.SM DEAD -is a very large number (effectively infinite), -.SM HIGH -and -.SM LOW -are \-5 and +5 respectively, -for baud-rate or quality bonuses/penalties, -and -.SM FAST -is \-80, for adjusting costs of links that use high-speed (9.6 Kbaud or more) modems. -These symbolic costs represent an imperfect measure of bandwidth, -monetary cost, and frequency of connections. -For most mail traffic, it is important to minimize the number -of hosts in a route, -thus, -.IR e.g. , -.SM HOURLY -\&* 24 -is much larger than -.SM DAILY. -If no cost is given, -a default of 4000 is used. -.PP -For the most part, arithmetic expressions that mix symbolic constants -other than -.SM HIGH, -.SM LOW, -and -.SM FAST -make no sense. -.IR E.g. , -if a host calls a local neighbor whenever there is work, -and additionally polls every evening, -the cost is -.SM DIRECT, -.B not -.SM DIRECT+EVENING. -.PP -Some examples: -.PP -.RS -.nf -.ta 10m 15m -down princeton!(\s-1DEDICATED\s0), tilt, - %thrash(\s-1LOCAL\s0) -princeton topaz!(\s-1DEMAND\s0+\s-1LOW\s0) -topaz @rutgers(\s-1LOCAL\s0+1) -.fi -.RE -.PP -If a link is encountered more than once, -the least-cost occurrence dictates the cost and network character. -Links are treated as bidirectional but asymmetric: -for each link declared in the input, a -.SM DEAD -reverse link is assumed. -.PP -If the ``to'' host in a link is surrounded by angle brackets, -the link is considered -.IR terminal , -and -further links beyond this one are heavily penalized. -.IR E.g. , -with input -.PP -.RS -.nf -.ta 10m 15m -seismo <research>(10), research(100), ihnp4(10) -research allegra(10) -ihnp4 allegra(50) -.fi -.RE -.PP -the path from seismo to research is direct, but the path from seismo -to allegra -uses ihnp4 as a relay, not research. -.PP -The set of names by which a host is known to its neighbors is -called its -.IR aliases . -Aliases are declared as follows: -.PP -.RS -name = alias, alias ... -.RE -.PP -The name used in the route to or through aliased hosts -is the name by which the host is known -to its predecessor in the route. -.PP -Fully connected networks, such as the -.SM ARPANET -or a local-area network, -are declared as follows: -.PP -.RS -net = {host, host, ...} -.RE -.PP -The host-list may be preceded or followed by a routing -character (`!' default), and may be followed by a cost (default 4000). -The network name is optional; if not given, -.I pathalias -makes one up. -.PP -.RS -.nf -etherhosts = {rahway, milan, joliet}!(\s-1LOCAL\s0) -ringhosts = @{gimli, alida, almo}(\s-1DEDICATED\s0) -= {etherhosts, ringhosts}(0) -.fi -.RE -.PP -The routing character used in a route to a network member is the one -encountered when ``entering'' the network. -See also the sections on -.I gateways -and -.I domains . -.PP -Connection data may be given while hiding host names -by declaring -.PP -.RS -private {host, host, ...} -.RE -.PP -.I Pathalias -will not generate routes for private hosts, but may produce routes -through them. -The scope of a private declaration extends from the declaration to the end of -the input file in which it appears, or to a private declaration with an empty -host list, whichever comes first. -The latter scope rule offers a way to retain the -semantics of private declarations when -reading from the standard input. -.PP -Dead hosts, links, or networks may be presented in the input stream by declaring -.PP -.RS -dead {arg, ...} -.RE -.PP -where -.I arg -has the same form as the argument to the -.B \-d -option. -.PP -To force a specific cost for a link, delete all prior declarations with -.PP -.RS -delete {host-1!host-2} -.RE -.PP -and declare the link as desired. -To delete a host and all its links, use -.PP -.RS -delete {host} -.RE -.PP -Error diagnostics refer to the file in which the error was found. -To alter the file name, use -.PP -.RS -file {filename} -.RE -.PP -Fine-tuning is possible by adjusting the weights -of all links from a given host, as in -.PP -.RS -adjust {host-1, host-2(LOW), host-3(\-1)} -.RE -.PP -If no cost is given a default of 4000 is used. -.PP -Input from compressed (and uncompressed) files can be -piped into -.I pathalias -with the following script. -.PP -.RS -.nf -for i in $*; do - case $i in - *.Z) echo "file {`expr $i : '\(.*\).Z'`} - zcat $i ;; - *) echo "file {$i}" - cat $i ;; - esac - echo "private {}" -done -.fi -.RE -.PP -.SS Output Format -A list of host-route pairs is written to the standard output, -where route is a string appropriate for use with -.IR printf (3), -.IR e.g. , -.PP -.RS -.nf -.ta 10m 20m -rutgers princeton!topaz!%s@rutgers -.fi -.RE -.PP -The ``%s'' in the route string should be replaced by the -user name at the destination host. -(This task is normally performed by a mailer.) -.PP -Except for -.IR domains , -the name of a network is never used in -routes. -Thus, in the earlier example, the path from down to -up would be ``up!%s,'' not ``princeton-ethernet!up!%s.'' -.SS Gateways -A network is represented by -a pseudo-host and a set of network members. -Links from the members to the network have the weight given in -the input, while the cost from the network to the members is zero. -If a network is declared dead, -the member-to-network links are marked dead, -which effectively prohibits access to the network -from its members. -.PP -However, if the input also shows an explicit link from any host to the network, -then that host can be used as a gateway. -(In particular, the gateway need not be a network member.) -.PP -.IR E.g. , -if -.SM CSNET -is declared dead -and the input contains -.PP -.RS -.nf -.ta 10m 20m -\s-1CSNET\s0 = {...} -csnet-relay \s-1CSNET\s0 -.fi -.RE -.PP -then routes to -.SM CSNET -hosts will use csnet-relay as a gateway. -.SS Domains -A network whose name begins with `.' is called -a domain. -Domains are presumed to require gateways, -.IR i.e. , -they are \s-1DEAD\s0. -The route given by a path through a domain is similar to -that for a network, but here -the domain name is tacked onto the end of the next host. -Subdomains are permitted. -.PP -.IR E.g. , -.PP -.RS -.nf -.ta 1i -.ta 10m 20m 30m -harvard .\s-1EDU\s0 # harvard is gateway to .EDU domain -\&.\s-1EDU\s0 = {.\s-1BERKELEY\s0, .\s-1UMICH\s0} -\&.\s-1BERKELEY\s0 = {ernie} -.fi -.RE -.PP -yields -.PP -.RS -.nf -.ta 10m 20m -ernie ...!harvard!ernie.\s-1BERKELEY\s0.\s-1EDU\s0!%s -.fi -.RE -.PP -Output is given for the nearest gateway -to a domain, -.IR e.g. , -the example above gives -.PP -.RS -.nf -.ta 10m 25m -\&.\s-1EDU\s0 ...!harvard!%s -.fi -.RE -.PP -Output is given for a subdomain if it has a different -route than its parent domain, or if all its ancestor domains are private. -.PP -If the -.B \-D -option is given on the command line, -.I pathalias -treats a link from a domain to a host member of that domain as terminal. -This property extends to host members of subdomains, -.IR etc , -and discourages -routes that use any domain member as a relay. -.SS Databases -.I Makedb -builds a -.IR dbm (3) -database from the standard input or from the named -.IR files . -Input is expected to be sequence of -.SM ASCII -records, -each consisting of a key field and a data field separated by a single tab. -If the tab is missing, the data field is assumed to be empty. -.SH FILES ET AL. -.ta \w'/usr/local/lib/palias.{dir,pag} 'u -/usr/local/lib/palias.{dir,pag} default dbm output -.br -newsgroup comp.mail.maps likely location of some input files -.br -.IR getopt (3), -available from comp.sources.unix archives (if not in the C library). -.SH BUGS -The -.B \-i -option should be the default. -.PP -The order of arguments is significant. -In particular, -.B \-i -and -.B \-t -should appear early. -.PP -.I Pathalias -can generate hybrid (\fIi.e.\fP ambiguous) routes, which are -abhorrent and most certainly should not be given as examples -in the manual entry. -Experienced mappers largely shun `@' when preparing input; this -is historical, but also reflects \s-1UUCP\s0's -facile syntax for source routes. -.PP -Multiple `@'s in routes are loathsome, so -.I pathalias -resorts to the ``magic %'' rule when necessary. -This convention is not documented anywhere, including here. -.PP -The -.B \-D -option elides insignificant routes to domain members. -This is benign, perhaps even beneficial, but confusing, since the -behavior is undocumented and somewhat unpredictable. -.SH SEE ALSO -P. Honeyman and S.M. Bellovin, ``\s-1PATHALIAS\s0 \fIor\fP The Care and Feeding -of Relative Addresses,'' -in \fIProc. Summer \s-1USENIX\s0 Conf.\fP, Atlanta, 1986. //GO.SYSIN DD pathalias.8 echo Makefile 1>&2 sed 's/^-//' >Makefile <<'//GO.SYSIN DD Makefile' -#!/bin/make -f -# pathalias -- by steve bellovin, as told to peter honeyman - -### begin configuration section -### -# if you can't or don't intend to use dbm files, -# don't bother with DBM or makedb -DBM = -ldbm -# or if you roll your own ... -# DBM = dbm.o -### -# where is getopt (if not in the c library)? -# GETOPT = getopt.o -### end of configuration section - - -CC = cc -CFLAGS = -O -LDFLAGS = -s $(GETOPT) -YFLAGS = -d - -OBJ = addlink.o addnode.o local.o main.o mapit.o mapaux.o mem.o parse.o printit.o -HDRS = def.h config.h -CSRC = addlink.c addnode.c local.c main.c mapit.c mapaux.c mem.c printit.c -LSRC = $(CSRC) parse.c -SRC = $(CSRC) parse.y makedb.c arpatxt.c - -pathalias: $(OBJ) - $(CC) $(OBJ) $(LDFLAGS) -o pathalias - -all: pathalias makedb arpatxt - -$(OBJ): $(HDRS) - -parse.c: parse.y $(HDRS) - $(YACC) $(YFLAGS) parse.y - mv y.tab.c parse.c - -makedb: makedb.o - $(CC) makedb.o $(LDFLAGS) $(DBM) -o makedb - -makedb.o: config.h - -arpatxt: arpatxt.o - $(CC) arpatxt.o $(LDFLAGS) -o arpatxt - -clean: - rm -f *.o y.tab.? parse.c - -clobber: clean - rm -f pathalias makedb arpatxt - -tags: $(SRC) $(HDRS) - ctags -w $(HDRS) $(SRC) - -bundle: - @bundle README CHANGES pathalias.1 Makefile ${HDRS} ${SRC} - -lint: $(LSRC) - lint $(CFLAGS) $(LSRC) - lint makedb.c - lint arpatxt.c - -install: - @echo "install pathalias, makedb, arpatxt, and pathalias.1" - @echo "according to local conventions" //GO.SYSIN DD Makefile echo def.h 1>&2 sed 's/^-//' >def.h <<'//GO.SYSIN DD def.h' -/* pathalias -- by steve bellovin, as told to peter honeyman */ - -#ifndef lint -#ifdef MAIN -static char *h_sccsid = "@(#)def.h 9.5 88/05/09"; -#endif /*MAIN*/ -#endif /*lint*/ - -#include <stdio.h> -#include <ctype.h> -#include "config.h" - -typedef long Cost; -typedef struct node node; -typedef struct link link; - -#ifdef lint -#define vprintf fprintf -#else /*!lint -- this gives null effect warning*/ -/* because it's there ... */ -#define vprintf !Vflag ? 0 : fprintf -#endif /*lint*/ - -#define NTRACE 16 /* can trace up to NTRACE hosts/links */ - -/* flags for n_flag */ -#define ISPRIVATE 0x0001 /* invisible outside its definition file */ -#define NALIAS 0x0002 /* heaped as an alias */ -#define ATSIGN 0x0004 /* seen an at sign? used for magic @/% rules */ -#define MAPPED 0x0008 /* extracted from heap */ -#define NDEAD 0x0010 /* out links are dead */ -#define HASLEFT 0x0020 /* has a left side net character */ -#define HASRIGHT 0x0040 /* route has a right side net character */ -#define NNET 0x0080 /* network pseudo-host */ -#define INDFS 0x0100 /* used when removing net cycles (for -g) */ -#define DUMP 0x0200 /* we have dumped this net's edges (for -g) */ -#define PRINTED 0x0400 /* this host has been printed */ -#define NTERMINAL 0x0800 /* heaped as terminal edge (or alias thereto) */ -#define NREF 0x1000 /* node has an "interesting" reference */ - -#define ISADOMAIN(n) ((n)->n_name[0] == '.') -#define ISANET(n) (((n)->n_flag & NNET) || ISADOMAIN(n)) -#define ALTEREGO(n1, n2) ((n1)->n_name == (n2)->n_name) -#define DEADHOST(n) (((n)->n_flag & (NDEAD | NTERMINAL)) && !ISANET(n)) -#define DEADLINK(l) ((l)->l_flag & LDEAD) -#define DEADNET(n) (((n)->n_flag & (NNET | NDEAD)) == (NNET | NDEAD)) -#define GATEWAYED(n) (DEADNET(n) || ISADOMAIN(n)) - -#ifndef DEBUG -/* - * save some space in nodes -- there are > 10,000 allocated! - */ - -#define n_root un1.nu_root -#define n_net un1.nu_net -#define n_copy un1.nu_copy - -#define n_private un2.nu_priv -#define n_parent un2.nu_par - -/* WARNING: if > 2^16 nodes, type of n_tloc must change */ -struct node { - char *n_name; /* host name */ - link *n_link; /* adjacency list */ - Cost n_cost; /* cost to this host */ - union { - node *nu_net; /* others in this network (parsing) */ - node *nu_root; /* root of net cycle (graph dumping) */ - node *nu_copy; /* circular copy list (mapping) */ - } un1; - union { - node *nu_priv; /* other privates in this file (parsing) */ - node *nu_par; /* parent in shortest path tree (mapping) */ - } un2; - unsigned short n_tloc; /* back ptr to heap/hash table */ - unsigned short n_flag; /* see manifests above */ -}; - -#endif /*DEBUG*/ - -#define MILLION (1000L * 1000L) -#define DEFNET '!' /* default network operator */ -#define DEFDIR LLEFT /* host on left is default */ -#define DEFCOST ((Cost) 4000) /* default cost of a link */ -#define INF ((Cost) 100 * MILLION) /* infinitely expensive link */ -#define DEFPENALTY ((Cost) 200) /* default avoidance cost */ - -/* data structure for adjacency list representation */ - -/* flags for l_dir */ - -#define NETDIR(l) ((l)->l_flag & LDIR) -#define NETCHAR(l) ((l)->l_netop) - -#define LDIR 0x0008 /* 0 for left, 1 for right */ -#define LRIGHT 0x0000 /* user@host style */ -#define LLEFT 0x0008 /* host!user style */ - -#define LDEAD 0x0010 /* this link is dead */ -#define LALIAS 0x0020 /* this link is an alias */ -#define LTREE 0x0040 /* member of shortest path tree */ -#define LGATEWAY 0x0080 /* this link is a gateway */ -#define LTERMINAL 0x0100 /* this link is terminal */ - -#ifndef DEBUG -/* - * borrow a field for link/node tracing. there's a shitload of - * edges -- every word counts. only so much squishing is possible: - * alignment dictates that the size be a multiple of four. - */ - -#define l_next un.lu_next -#define l_from un.lu_from - -struct link { - node *l_to; /* adjacent node */ - Cost l_cost; /* edge cost */ - union { - link *lu_next; /* rest of adjacency list (not tracing) */ - node *lu_from; /* source node (tracing) */ - } un; - short l_flag; /* right/left syntax, flags */ - char l_netop; /* network operator */ -}; - -#endif /*DEBUG*/ - -#ifdef DEBUG -/* - * flattening out the unions makes it easier - * to debug (when pi is unavailable). - */ -struct node { - char *n_name; - link *n_link; - Cost n_cost; - node *n_net; - node *n_root; - node *n_copy; - node *n_private; - node *n_parent; - unsigned short n_tloc; - unsigned short n_flag; -}; -struct link { - node *l_to; - Cost l_cost; - link *l_next; - node *l_from; - short l_flag; - char l_netop; -}; -#endif /*DEBUG*/ //GO.SYSIN DD def.h echo config.h 1>&2 sed 's/^-//' >config.h <<'//GO.SYSIN DD config.h' -/* pathalias -- by steve bellovin, as told to peter honeyman */ - -/************************************************************************** - * +--------------------------------------------------------------------+ * - * | begin configuration section | * - * +--------------------------------------------------------------------+ * - **************************************************************************/ - -#undef STRCHR /* have strchr -- system v and many others */ - -#undef UNAME /* have uname() -- probably system v or 8th ed. */ -#undef MEMSET /* have memset() -- probably system v or 8th ed. */ - -#define GETHOSTNAME /* have gethostname() -- probably bsd */ -#define BZERO /* have bzero() -- probably bsd */ - -/* default place for dbm output of makedb (or use -o at run-time) */ -#define ALIASDB "/usr/local/lib/palias" - -/************************************************************************** - * +--------------------------------------------------------------------+ * - * | end of configuration section | * - * +--------------------------------------------------------------------+ * - **************************************************************************/ - - - -#ifdef MAIN -#ifndef lint -static char *c_sccsid = "@(#)config.h 9.2 89/03/03"; -#endif /*lint*/ -#endif /*MAIN*/ - -/* - * malloc/free fine tuned for pathalias. - * - * MYMALLOC should work everwhere, so it's not a configuration - * option (anymore). nonetheless, if you're getting strange - * core dumps (or panics!), comment out the following manifest, - * and use the inferior C library malloc/free. - */ -#define MYMALLOC /**/ - -#ifdef MYMALLOC -#define malloc mymalloc -#define calloc(n, s) malloc ((n)*(s)) -#define free(s) -#define cfree(s) -extern char *memget(); -#else /* !MYMALLOC */ -extern char *calloc(); -#endif /* MYMALLOC */ - -#ifdef STRCHR -#define index strchr -#define rindex strrchr -#else -#define strchr index -#define strrchr rindex -#endif - -#ifdef BZERO -#define strclear(s, n) ((void) bzero((s), (n))) -#else /*!BZERO*/ - -#ifdef MEMSET -extern char *memset(); -#define strclear(s, n) ((void) memset((s), 0, (n))) -#else /*!MEMSET*/ -extern void strclear(); -#endif /*MEMSET*/ - -#endif /*BZERO*/ - -extern char *malloc(); -extern char *strcpy(), *index(), *rindex(); - -#ifndef STATIC - -#ifdef DEBUG -#define STATIC extern -#else /*DEBUG*/ -#define STATIC static -#endif /*DEBUG*/ - -#endif /*STATIC*/ //GO.SYSIN DD config.h echo addlink.c 1>&2 sed 's/^-//' >addlink.c <<'//GO.SYSIN DD addlink.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)addlink.c 9.7 88/06/10"; -#endif /* lint */ - -#include "def.h" - -/* exports */ -extern link *addlink(); -extern void deadlink(), atrace(), freelink(); -extern int tracelink(), maptrace(); -char *Netchars = "!:@%"; /* sparse, but sufficient */ -long Lcount; /* how many edges? */ - -/* imports */ -extern int Tflag, Dflag; -extern link *newlink(); -extern node *addnode(); -extern void yyerror(), die(); -extern int strcmp(), strlen(); - -/* privates */ -STATIC void netbits(), ltrace(), ltrprint(); -static link *Trace[NTRACE]; -static int Tracecount; - -#define EQ(n1, n2) (strcmp((n1)->n_name, (n2)->n_name) == 0) -#define LTRACE if (Tflag) ltrace - -link * -addlink(from, to, cost, netchar, netdir) - node *from; - register node *to; - Cost cost; - char netchar, netdir; -{ register link *l, *prev = 0; - - LTRACE(from, to, cost, netchar, netdir, ""); - /* - * maintain uniqueness for dead links (only). - */ - for (l = from->n_link; l; l = l->l_next) { - if (!DEADLINK(l)) - break; - if (to == l->l_to) { - /* what the hell, use cheaper dead cost */ - if (cost < l->l_cost) { - l->l_cost = cost; - netbits(l, netchar, netdir); - } - return l; - } - prev = l; - } - - - /* allocate and link in the new link struct */ - l = newlink(); - if (cost != INF) /* ignore back links */ - Lcount++; - if (prev) { - l->l_next = prev->l_next; - prev->l_next = l; - } else { - l->l_next = from->n_link; - from->n_link = l; - } - - l->l_to = to; - /* add penalty */ - if ((l->l_cost = cost + from->n_cost) < 0) { - char buf[100]; - - l->l_flag |= LDEAD; - sprintf(buf, "link to %s ignored with negative cost", to->n_name); - yyerror(buf); - } - if (netchar == 0) { - netchar = DEFNET; - netdir = DEFDIR; - } - netbits(l, netchar, netdir); - if (Dflag && ISADOMAIN(from)) - l->l_flag |= LTERMINAL; - - return l; -} - -void -deadlink(nleft, nright) - node *nleft, *nright; -{ link *l, *lhold = 0, *lprev, *lnext; - - /* DEAD host */ - if (nright == 0) { - nleft->n_flag |= NDEAD; /* DEAD host */ - return; - } - - /* DEAD link */ - - /* grab <nleft, nright> instances at head of nleft adjacency list */ - while ((l = nleft->n_link) != 0 && l->l_to == nright) { - nleft->n_link = l->l_next; /* disconnect */ - l->l_next = lhold; /* terminate */ - lhold = l; /* add to lhold */ - } - - /* move remaining <nleft, nright> instances */ - for (lprev = nleft->n_link; lprev && lprev->l_next; lprev = lprev->l_next) { - if (lprev->l_next->l_to == nright) { - l = lprev->l_next; - lprev->l_next = l->l_next; /* disconnect */ - l->l_next = lhold; /* terminate */ - lhold = l; - } - } - - /* check for emptiness */ - if (lhold == 0) { - addlink(nleft, nright, INF / 2, DEFNET, DEFDIR)->l_flag |= LDEAD; - return; - } - - /* reinsert deleted edges as DEAD links */ - for (l = lhold; l; l = lnext) { - lnext = l->l_next; - addlink(nleft, nright, l->l_cost, NETCHAR(l), NETDIR(l))->l_flag |= LDEAD; - freelink(l); - } -} - -STATIC void -netbits(l, netchar, netdir) - register link *l; - char netchar, netdir; -{ - l->l_flag &= ~LDIR; - l->l_flag |= netdir; - l->l_netop = netchar; -} - -int -tracelink(arg) - char *arg; -{ char *bang; - link *l; - - if (Tracecount >= NTRACE) - return -1; - l = newlink(); - bang = index(arg, '!'); - if (bang) { - *bang = 0; - l->l_to = addnode(bang+1); - } else - l->l_to = 0; - - l->l_from = addnode(arg); - Trace[Tracecount++] = l; - return 0; -} - -/* - * the obvious choice for testing equality is to compare struct - * addresses, but that misses private nodes, so we use strcmp(). - */ - -STATIC void -ltrace(from, to, cost, netchar, netdir, message) - node *from, *to; - Cost cost; - char netchar, netdir, *message; -{ link *l; - int i; - - for (i = 0; i < Tracecount; i++) { - l = Trace[i]; - /* overkill, but you asked for it! */ - if (l->l_to == 0) { - if (EQ(from, l->l_from) || EQ(to, l->l_from)) - break; - } else if (EQ(from, l->l_from) && EQ(to, l->l_to)) - break; - else if (EQ(from, l->l_to) && EQ(to, l->l_from)) - break; /* potential dead backlink */ - } - if (i < Tracecount) - ltrprint(from, to, cost, netchar, netdir, message); -} - -/* print a trace item */ -STATIC void -ltrprint(from, to, cost, netchar, netdir, message) - node *from, *to; - Cost cost; - char netchar, netdir, *message; -{ char buf[256], *bptr = buf; - - strcpy(bptr, from->n_name); - bptr += strlen(bptr); - *bptr++ = ' '; - if (netdir == LRIGHT) /* @% */ - *bptr++ = netchar; - strcpy(bptr, to->n_name); - bptr += strlen(bptr); - if (netdir == LLEFT) /* !: */ - *bptr++ = netchar; - sprintf(bptr, "(%ld) %s", cost, message); - yyerror(buf); -} - -void -atrace(n1, n2) - node *n1, *n2; -{ link *l; - int i; - char buf[256]; - - for (i = 0; i < Tracecount; i++) { - l = Trace[i]; - if (l->l_to == 0 && ((node *) l->l_from == n1 || (node *) l->l_from == n2)) { - sprintf(buf, "%s = %s", n1->n_name, n2->n_name); - yyerror(buf); - return; - } - } -} - -int -maptrace(from, to) - register node *from, *to; -{ register link *l; - register int i; - - for (i = 0; i < Tracecount; i++) { - l = Trace[i]; - if (l->l_to == 0) { - if (EQ(from, l->l_from) || EQ(to, l->l_from)) - return 1; - } else if (EQ(from, l->l_from) && EQ(to, l->l_to)) - return 1; - } - return 0; -} - -void -deletelink(from, to) - node *from; - node *to; -{ register link *l, *lnext; - - l = from->n_link; - - /* delete all neighbors of from */ - if (to == 0) { - while (l) { - LTRACE(from, l->l_to, l->l_cost, NETCHAR(l), NETDIR(l), "DELETED"); - lnext = l->l_next; - freelink(l); - l = lnext; - } - from->n_link = 0; - return; - } - - /* delete from head of list */ - while (l && EQ(to, l->l_to)) { - LTRACE(from, to, l->l_cost, NETCHAR(l), NETDIR(l), "DELETED"); - lnext = l->l_next; - freelink(l); - l = from->n_link = lnext; - } - - /* delete from interior of list */ - if (l == 0) - return; - for (lnext = l->l_next; lnext; lnext = l->l_next) { - if (EQ(to, lnext->l_to)) { - LTRACE(from, to, l->l_cost, NETCHAR(l), NETDIR(l), "DELETED"); - l->l_next = lnext->l_next; - freelink(lnext); - /* continue processing this link */ - } else - l = lnext; /* next link */ - } -} //GO.SYSIN DD addlink.c echo addnode.c 1>&2 sed 's/^-//' >addnode.c <<'//GO.SYSIN DD addnode.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)addnode.c 9.6 89/05/05"; -#endif - -#include "def.h" - -#define EQ(n, s) (*(n)->n_name == *(s) && strcmp((n)->n_name, (s)) == 0) - -/* exports */ -node *addnode(), *addprivate(); -void alias(), hashanalyze(), fixprivate(); -node **Table; /* hash table ^ priority queue */ -long Tabsize; /* size of Table */ - -/* imports */ -extern link *addlink(); -extern node *newnode(), **newtable(); -extern char *strsave(); -extern int Iflag, Tflag, Vflag; -extern node **Table; -extern long Ncount, Tabsize; -extern char **Argv; -extern void atrace(), die(), freetable(); -extern int strcmp(); - -/* privates */ -STATIC void crcinit(), rehash(), lowercase(); -STATIC long fold(); -STATIC long hash(); -STATIC node *isprivate(); -static node *Private; /* list of private nodes in current input file */ -/* - * these numbers are chosen because: - * -> they are prime, - * -> they are monotonic increasing, - * -> each is a tad smaller than a multiple of 1024, - * -> they form a fibonacci sequence (almost). - * the first point yields good hash functions, the second is used for the - * standard re-hashing implementation of open addressing, the third - * optimizes for quirks in some mallocs i have seen, and the fourth simply - * appeals to me. - */ -static long Primes[] = { - 1021, 2039, 3067, 5113, 8179, 13309, 21499, 34807, 56311, 0 -}; - -static int Tabindex; -static long Tab128; /* Tabsize * 128 */ - -node * -addnode(name) - register char *name; -{ register long i; - register node *n; - - if (Iflag) - lowercase(name); - - /* is it a private host? */ - n = isprivate(name); - if (n) - return n; - - i = hash(name, 0); - if (Table[i]) - return Table[i]; - - n = newnode(); - n->n_name = strsave(name); - Table[i] = n; - n->n_tloc = i; /* essentially a back link to the table */ - - return n; -} - -void -alias(n1, n2) - node *n1, *n2; -{ - link *l; - - if (ISADOMAIN(n1) && ISADOMAIN(n2)) { - fprintf(stderr, "%s: domain alias %s = %s is illegal\n", Argv[0], n1->n_name, n2->n_name); - return; - } - l = addlink(n1, n2, (Cost) 0, DEFNET, DEFDIR); - l->l_flag |= LALIAS; - l = addlink(n2, n1, (Cost) 0, DEFNET, DEFDIR); - l->l_flag |= LALIAS; - if (Tflag) - atrace(n1, n2); -} - -/* - * fold a string into a long int. 31 bit crc (from andrew appel). - * the crc table is computed at run time by crcinit() -- we could - * precompute, but it takes 1 clock tick on a 750. - * - * This fast table calculation works only if POLY is a prime polynomial - * in the field of integers modulo 2. Since the coefficients of a - * 32-bit polynomail won't fit in a 32-bit word, the high-order bit is - * implicit. IT MUST ALSO BE THE CASE that the coefficients of orders - * 31 down to 25 are zero. Happily, we have candidates, from - * E. J. Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962): - * x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0 - * x^31 + x^3 + x^0 - * - * We reverse the bits to get: - * 111101010000000000000000000000001 but drop the last 1 - * f 5 0 0 0 0 0 0 - * 010010000000000000000000000000001 ditto, for 31-bit crc - * 4 8 0 0 0 0 0 0 - */ - -#define POLY32 0xf5000000 /* 32-bit polynomial */ -#define POLY31 0x48000000 /* 31-bit polynomial */ -#define POLY POLY31 /* use 31-bit to avoid sign problems */ - -static long CrcTable[128]; - -STATIC void -crcinit() -{ register int i,j; - register long sum; - - for (i = 0; i < 128; i++) { - sum = 0; - for (j = 7-1; j >= 0; --j) - if (i & (1 << j)) - sum ^= POLY >> j; - CrcTable[i] = sum; - } -} - -STATIC long -fold(s) - register char *s; -{ register long sum = 0; - register int c; - - while ((c = *s++) != 0) - sum = (sum >> 7) ^ CrcTable[(sum ^ c) & 0x7f]; - return sum; -} - - -#define HASH1(n) ((n) % Tabsize); -#define HASH2(n) (Tabsize - 2 - ((n) % (Tabsize-2))) /* sedgewick */ - -/* - * when alpha is 0.79, there should be 2 probes per access (gonnet). - * use long constant to force promotion. Tab128 biases HIGHWATER by - * 128/100 for reduction in strength in isfull(). - */ -#define HIGHWATER 79L -#define isfull(n) ((n) * 128 >= Tab128) - -STATIC long -hash(name, unique) - char *name; - int unique; -{ register long probe; - register long hash2; - register node *n; - - if (isfull(Ncount)) { - if (Tabsize == 0) { /* first time */ - crcinit(); - Tabindex = 0; - Tabsize = Primes[0]; - Table = newtable(Tabsize); - Tab128 = (HIGHWATER * Tabsize * 128L)/100L; - } else - rehash(); /* more, more! */ - } - - probe = fold(name); - hash2 = HASH2(probe); - probe = HASH1(probe); - - /* - * probe the hash table. - * if unique is set, we require a fresh slot. - * otherwise, use double hashing to find either - * (1) an empty slot, or - * (2) a non-private copy of this host name - * - * this is an "inner loop." - */ - while ((n = Table[probe]) != 0) { - if (EQ(n, name) && !(n->n_flag & ISPRIVATE) && !unique) - return probe; /* this is it! */ - - probe -= hash2; /* double hashing */ - if (probe < 0) - probe += Tabsize; - } - return probe; /* brand new */ -} - -STATIC void -rehash() -{ register node **otable, **optr; - register long probe; - long osize; - -#ifdef DEBUG - hashanalyze(); -#endif - optr = Table + Tabsize - 1; /* ptr to last */ - otable = Table; - osize = Tabsize; - Tabsize = Primes[++Tabindex]; - if (Tabsize == 0) - die("too many hosts"); /* need more prime numbers */ - vprintf(stderr, "rehash into %d\n", Tabsize); - Table = newtable(Tabsize); - Tab128 = (HIGHWATER * Tabsize * 128L)/100L; - - do { - if (*optr == 0) - continue; /* empty slot in old table */ - probe = hash((*optr)->n_name, - ((*optr)->n_flag & ISPRIVATE) != 0); - if (Table[probe] != 0) - die("rehash error"); - Table[probe] = *optr; - (*optr)->n_tloc = probe; - } while (optr-- > otable); - freetable(otable, osize); -} - -void -hashanalyze() -#if 0 -{ long probe, hash2; - int count, i, collision[8]; - int longest = 0, total = 0, slots = 0, longprobe = 0; - int nslots = sizeof(collision)/sizeof(collision[0]); - - if (!Vflag) - return; - - strclear((char *) collision, sizeof(collision)); - for (i = 0; i < Tabsize; i++) { - if (Table[i] == 0) - continue; - /* private hosts too hard to account for ... */ - if (Table[i]->n_flag & ISPRIVATE) - continue; - count = 1; - probe = fold(Table[i]->n_name); - /* don't change the order of the next two lines */ - hash2 = HASH2(probe); - probe = HASH1(probe); - /* thank you! */ - while (Table[probe] != 0 - && strcmp(Table[probe]->n_name, Table[i]->n_name) != 0) { - count++; - probe -= hash2; - if (probe < 0) - probe += Tabsize; - } - if (Table[probe] == 0) - die("impossible hash error"); - - total += count; - slots++; - if (count > longest) { - longest = count; - longprobe = i; - } - if (count >= nslots) - count = 0; - collision[count]++; - } - for (i = 1; i < nslots; i++) - if (collision[i]) - fprintf(stderr, "%d chains: %d (%ld%%)\n", - i, collision[i], (collision[i] * 100L)/ slots); - if (collision[0]) - fprintf(stderr, "> %d chains: %d (%ld%%)\n", - nslots - 1, collision[0], - (collision[0] * 100L)/ slots); - fprintf(stderr, "%2.2f probes per access, longest chain: %d, %s\n", - (double) total / slots, longest, Table[longprobe]->n_name); - if (Vflag < 2) - return; - probe = fold(Table[longprobe]->n_name); - hash2 = HASH2(probe); - probe = HASH1(probe); - while (Table[probe] != 0 - && strcmp(Table[probe]->n_name, Table[longprobe]->n_name) != 0) { - fprintf(stderr, "%5d %s\n", probe, Table[probe]->n_name); - probe -= hash2; - if (probe < 0) - probe += Tabsize; - } - fprintf(stderr, "%5d %s\n", probe, Table[probe]->n_name); - -} -#else -{ - /* the hash algorithms are perfect -- leave them alone */ -} -#endif - -/* convert to lower case in place */ -STATIC void -lowercase(s) - register char *s; -{ - do { - if (isupper(*s)) - *s -= 'A' - 'a'; /* ASCII */ - } while (*s++); -} - -/* - * this might need change if privates catch on - */ -STATIC node * -isprivate(name) - register char *name; -{ register node *n; - - for (n = Private; n != 0; n = n->n_private) - if (strcmp(name, n->n_name) == 0) - return n; - return 0; -} - -/* Add a private node so private that nobody can find it. */ -node * -addhidden(name) - register char *name; -{ register node *n; - register int i; - if (Iflag) - lowercase(name); - - n = newnode(); - n->n_name = strsave(name); - n->n_flag = ISPRIVATE; - i = hash(n->n_name, 1); - if (Table[i] != 0) - die("impossible hidden node error"); - Table[i] = n; - n->n_tloc = i; - n->n_private = 0; - return n; -} - -void -fixprivate() -{ register node *n, *next; - register long i; - - for (n = Private; n != 0; n = next) { - n->n_flag |= ISPRIVATE; /* overkill, but safe */ - i = hash(n->n_name, 1); - if (Table[i] != 0) - die("impossible private node error"); - - Table[i] = n; - n->n_tloc = i; /* essentially a back link to the table */ - next = n->n_private; - n->n_private = 0; /* clear for later use */ - } - Private = 0; -} - -node * -addprivate(name) - register char *name; -{ register node *n; - - if (Iflag) - lowercase(name); - if ((n = isprivate(name)) != 0) - return n; - - n = newnode(); - n->n_name = strsave(name); - n->n_private = Private; - Private = n; - return n; -} //GO.SYSIN DD addnode.c echo local.c 1>&2 sed 's/^-//' >local.c <<'//GO.SYSIN DD local.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)local.c 9.2 88/06/10"; -#endif /* lint */ - -#include <stdio.h> -#include "config.h" - -#ifdef UNAME -#include <sys/utsname.h> - -char * -local() -{ - static struct utsname utsname; - extern int uname(); - - (void) uname(&utsname); - return(utsname.nodename); -} - -#else /* !UNAME */ - -char * -local() -{ - static char lname[64]; - extern int gethostname(); - - (void) gethostname(lname, (int) sizeof(lname)); - lname[sizeof(lname)] = 0; - return(lname); -} - -#ifndef GETHOSTNAME - -STATIC int -gethostname(name, len) - char *name; - int len; -{ FILE *whoami; - char *ptr; - extern int pclose(); - extern FILE *fopen(), *popen(); - - *name = '\0'; - - /* try /etc/whoami */ - if ((whoami = fopen("/etc/whoami", "r")) != 0) { - (void) fgets(name, len, whoami); - (void) fclose(whoami); - if ((ptr = index(name, '\n')) != 0) - *ptr = '\0'; - } - if (*name) - return 0; - - /* try /usr/include/whoami.h */ - if ((whoami = fopen("/usr/include/whoami.h", "r")) != 0) { - while (!feof(whoami)) { - char buf[100]; - - if (fgets(buf, 100, whoami) == 0) - break; - if (sscanf(buf, "#define sysname \"%[^\"]\"", name)) - break; - } - (void) fclose(whoami); - if (*name) - return 0; - } - - /* ask uucp */ - if ((whoami = popen("uuname -l", "r")) != 0) { - (void) fgets(name, len, whoami); - (void) pclose(whoami); - if ((ptr = index(name, '\n')) != 0) - *ptr = '\0'; - } - if (*name) - return 0; - - /* aw hell, i give up! is this really unix? */ - return -1; -} -#endif /* GETHOSTNAME */ -#endif /* UNAME */ //GO.SYSIN DD local.c echo main.c 1>&2 sed 's/^-//' >main.c <<'//GO.SYSIN DD main.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)main.c 9.5 88/06/10"; -#endif - -#define MAIN /* for sccsid in header files */ - -#include "def.h" - -/* exports */ -char *Cfile; /* current input file */ -char *Graphout; /* file for dumping edges (-g option) */ -char *Linkout; /* file for dumping shortest path tree */ -char **Argv; /* external copy of argv (for input files) */ -node *Home; /* node for local host */ -int Cflag; /* print costs (-c option) */ -int Dflag; /* penalize routes beyond domains (-D option) */ -int Iflag; /* ignore case (-i option) */ -int Tflag; /* trace links (-t option) */ -int Vflag; /* verbose (-v option) */ -int Fflag; /* print cost of first hop */ -int Lineno = 1; /* line number within current input file */ -int Argc; /* external copy of argc (for input files) */ -extern void die(); -extern int tracelink(); - -/* imports */ -extern char *optarg; -extern int optind; -extern long Lcount, Ncount; -extern long allocation(); -extern void wasted(), mapit(), hashanalyze(), deadlink(); -extern char *local(); -extern node *addnode(); -extern int getopt(), yyparse(); -extern void printit(); - -#define USAGE "usage: %s [-vciDf] [-l localname] [-d deadlink] [-t tracelink] [-g edgeout] [-s treeout] [-a avoid] [files ...]\n" - -main(argc, argv) - register int argc; - register char **argv; -{ char *locname = 0, *bang; - register int c; - int errflg = 0; - - setbuf(stderr, (char *) 0); - (void) allocation(); /* initialize data space monitoring */ - Cfile = "[deadlinks]"; /* for tracing dead links */ - Argv = argv; - Argc = argc; - - while ((c = getopt(argc, argv, "cd:Dfg:il:s:t:v")) != EOF) - switch(c) { - case 'c': /* print cost info */ - Cflag++; - break; - case 'd': /* dead host or link */ - if ((bang = index(optarg, '!')) != 0) { - *bang++ = 0; - deadlink(addnode(optarg), addnode(bang)); - } else - deadlink(addnode(optarg), (node *) 0); - break; - case 'D': /* penalize routes beyond domains */ - Dflag++; - break; - case 'f': /* print cost of first hop */ - Cflag++; - Fflag++; - break; - case 'g': /* graph output file */ - Graphout = optarg; - break; - case 'i': /* ignore case */ - Iflag++; - break; - case 'l': /* local name */ - locname = optarg; - break; - case 's': /* show shortest path tree */ - Linkout = optarg; - break; - case 't': /* trace this link */ - if (tracelink(optarg) < 0) { - fprintf(stderr, "%s: can trace only %d links\n", Argv[0], NTRACE); - exit(1); - } - Tflag = 1; - break; - case 'v': /* verbose stderr, mixed blessing */ - Vflag++; - break; - default: - errflg++; - } - - if (errflg) { - fprintf(stderr, USAGE, Argv[0]); - exit(1); - } - argv += optind; /* kludge for yywrap() */ - - if (*argv) - freopen("/dev/null", "r", stdin); - else - Cfile = "[stdin]"; - - if (!locname) - locname = local(); - if (*locname == 0) { - locname = "lostinspace"; - fprintf(stderr, "%s: using \"%s\" for local name\n", - Argv[0], locname); - } - - Home = addnode(locname); /* add home node */ - Home->n_cost = 0; /* doesn't cost to get here */ - - (void) yyparse(); /* read in link info */ - - if (Vflag > 1) - hashanalyze(); - vprintf(stderr, "%d nodes, %d links, alloc %ldk\n", - Ncount, Lcount, allocation()); - - Cfile = "[backlinks]"; /* for tracing back links */ - Lineno = 0; - - /* compute shortest path tree */ - mapit(); - vprintf(stderr, "allocation is %ldk after mapping\n", allocation()); - - /* traverse tree and print paths */ - printit(); - vprintf(stderr, "allocation is %ldk after printing\n", allocation()); - - wasted(); /* how much was wasted in memory allocation? */ - - return 0; -} - -void -die(s) - char *s; -{ -#ifdef DEBUG - extern int abort(); - - fprintf(stderr, "%s: %s\n", Argv[0], s); - fflush(stdout); - fflush(stderr); - abort(); -#else - fprintf(stderr, "%s: %s; notify the authorities\n", Argv[0], s); - exit(-1); -#endif -} //GO.SYSIN DD main.c echo mapit.c 1>&2 sed 's/^-//' >mapit.c <<'//GO.SYSIN DD mapit.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)mapit.c 9.13 88/06/12"; -#endif - -#include "def.h" - -#define chkheap(i) /* void */ -#define chkgap() /* int */ - -#define trprint(stream, n) \ - fprintf((stream), (n)->n_flag & NTERMINAL ? "<%s>" : "%s", (n)->n_name) - -/* exports */ -/* invariant while mapping: Nheap < Hashpart */ -long Hashpart; /* start of unreached nodes */ -long Nheap; /* end of heap */ -long NumNcopy, Nlink, NumLcopy; - -void mapit(); - -/* imports */ -extern long Nheap, Hashpart, Tabsize, Tcount; -extern int Tflag, Vflag; -extern node **Table, *Home; -extern char *Linkout, *Graphout; - -extern void freelink(), resetnodes(), printit(), dumpgraph(); -extern void showlinks(), die(); -extern long pack(), allocation(); -extern link *newlink(), *addlink(); -extern int maptrace(), tiebreaker(); -extern node *ncopy(); - - -/* privates */ -static long Heaphighwater; -static link **Heap; - -STATIC void insert(), heapup(), heapdown(), heapswap(), backlinks(); -STATIC void setheapbits(), mtracereport(), heapchildren(), otracereport(); -STATIC link *min_node(); -STATIC int dehash(), skiplink(), skipterminalalias(); -STATIC Cost costof(); -STATIC node *mappedcopy(); - -/* transform the graph to a shortest-path tree by marking tree edges */ -void -mapit() -{ register node *n; - register link *l; - - vprintf(stderr, "*** mapping\ttcount = %ld\n", Tcount); - Tflag = Tflag && Vflag; /* tracing here only if verbose */ - /* re-use the hash table space for the heap */ - Heap = (link **) Table; - Hashpart = pack(0L, Tabsize - 1); - - /* expunge penalties from -a option and make circular copy lists */ - resetnodes(); - - if (Linkout && *Linkout) /* dump cheapest links */ - showlinks(); - if (Graphout && *Graphout) /* dump the edge list */ - dumpgraph(); - - /* insert Home to get things started */ - l = newlink(); /* link to get things started */ - l->l_to = Home; - (void) dehash(Home); - insert(l); - - /* main mapping loop */ - do { - Heaphighwater = Nheap; - while ((l = min_node()) != 0) { - l->l_flag |= LTREE; - n = l->l_to; - if (n->n_flag & MAPPED) /* sanity check */ - die("mapped node in heap"); - if (Tflag && maptrace(n, n)) - otracereport(n); /* tracing */ - chkheap(1); chkgap(); /* debugging */ - n->n_flag |= MAPPED; - heapchildren(n); /* add children to heap */ - } - vprintf(stderr, "heap hiwat %d\nalloc %ldk, ncopy = %ld, nlink = %ld, lcopy = %ld\n", Heaphighwater, allocation(), NumNcopy, Nlink, NumLcopy); - - if (Nheap != 0) /* sanity check */ - die("null entry in heap"); - - /* - * add back links from unreachable hosts to reachable - * neighbors, then remap. asymptotically, this is - * quadratic; in practice, this is done once or twice, - * when n is small. - */ - backlinks(); - } while (Nheap > 0); - - if (Hashpart < Tabsize) { - int foundone = 0; - - for ( ; Hashpart < Tabsize; Hashpart++) { - if (Table[Hashpart]->n_flag & ISPRIVATE) - continue; - if (foundone++ == 0) - fputs("You can't get there from here:\n", stderr); - putc('\t', stderr); - trprint(stderr, Table[Hashpart]); - putc('\n', stderr); - } - } -} - -STATIC void -heapchildren(n) - register node *n; -{ register link *l; - register node *next; - register int mtrace; - register Cost cost; - - for (l = n->n_link; l; l = l->l_next) { - - next = l->l_to; /* neighboring node */ - mtrace = Tflag && maptrace(n, next); - - if (l->l_flag & LTREE) - continue; - - if (l->l_flag & LTERMINAL) - l->l_to = next = ncopy(n, l); - - if ((n->n_flag & NTERMINAL) && (l->l_flag & LALIAS)) - if (skipterminalalias(n, next)) - continue; - else - l->l_to = next = ncopy(n, l); - - if (next->n_flag & MAPPED) { - if (mtrace) - mtracereport(n, l, "-\talready mapped"); - continue; - } - cost = costof(n, l); - - if (skiplink(l, n, cost, mtrace)) - continue; - - /* - * put this link in the heap and restore the - * heap property. - */ - if (mtrace) { - if (next->n_parent) - mtracereport(next->n_parent, l, "*\tdrop"); - mtracereport(n, l, "+\tadd"); - } - next->n_parent = n; - if (dehash(next) == 0) { /* first time */ - next->n_cost = cost; - insert(l); /* insert at end */ - heapup(l); - } else { - /* replace inferior path */ - Heap[next->n_tloc] = l; - if (cost > next->n_cost) { - /* increase cost (gateway) */ - next->n_cost = cost; - heapdown(l); - } else if (cost < next->n_cost) { - /* cheaper route */ - next->n_cost = cost; - - heapup(l); - } - } - setheapbits(l); - chkheap(1); - - } -} - -/* - * bizarro special case. this merits comment. - * - * n is a terminal node just sucked out of the heap, next is an alias - * for n. because n is terminal, it must have one or more "copies." - * if next is one of those copies, don't put next in the heap. - * - * does that clear things up? - */ -STATIC int -skipterminalalias(n, next) - node *n, *next; -{ - - while (n->n_flag & NALIAS) { - n = n->n_parent; - if (ALTEREGO(n, next)) - return 1; - } - return 0; -} - -/* - * return 1 if we definitely don't want want this link in the - * shortest path tree, 0 if we might want it, i.e., best so far. - * - * if tracing is turned on, report only if this node is being skipped. - */ -STATIC int -skiplink(l, parent, cost, trace) - link *l; /* new link to this node */ - node *parent; /* (potential) new parent of this node */ - register Cost cost; /* new cost to this node */ - int trace; /* trace this link? */ -{ register node *n; /* this node */ - register link *lheap; /* old link to this node */ - - n = l->l_to; - - /* first time we've reached this node? */ - if (n->n_tloc >= Hashpart) - return 0; - - lheap = Heap[n->n_tloc]; - - /* examine links to nets that require gateways */ - if (GATEWAYED(n)) { - /* if exactly one is a gateway, use it */ - if ((lheap->l_flag & LGATEWAY) && !(l->l_flag & LGATEWAY)) { - if (trace) - mtracereport(parent, l, "-\told gateway"); - return 1; /* old is gateway */ - } - if (!(lheap->l_flag & LGATEWAY) && (l->l_flag & LGATEWAY)) - return 0; /* new is gateway */ - - /* no gateway or both gateways; resolve in standard way ... */ - } - - /* examine dup link (sanity check) */ - if (n->n_parent == parent && (DEADLINK(lheap) || DEADLINK(l))) - die("dup dead link"); - - /* examine cost */ - if (cost < n->n_cost) - return 0; - if (cost > n->n_cost) { - if (trace) - mtracereport(parent, l, "-\tcheaper"); - return 1; - } - - /* all other things being equal, ask the oracle */ - if (tiebreaker(n, parent)) { - if (trace) - mtracereport(parent, l, "-\ttiebreaker"); - return 1; - } - return 0; -} - -/* compute cost to l->l_to via parent */ -STATIC Cost -costof(prev, l) - register node *prev; - register link *l; -{ register node *next; - register Cost cost; - - if (l->l_flag & LALIAS) - return prev->n_cost; /* by definition */ - - next = l->l_to; - cost = prev->n_cost + l->l_cost; /* basic cost */ - - /* - * heuristics: - * charge for a dead link. - * charge for getting past a terminal host - * or getting out of a dead host. - * charge for getting into a gatewayed net (except at a gateway). - * discourage mixing of syntax (when prev is a host). - * - * life was simpler when pathalias computed true shortest paths. - */ - if (DEADLINK(l)) - cost += INF; /* dead link */ - if (DEADHOST(prev)) - cost += INF; /* dead parent */ - if (GATEWAYED(next) && !(l->l_flag & LGATEWAY)) - cost += INF; /* not gateway */ - if (!ISANET(prev)) { - if ((NETDIR(l) == LLEFT && (prev->n_flag & HASRIGHT)) - || (NETDIR(l) == LRIGHT && (prev->n_flag & HASLEFT))) - cost += INF; /* mixed syntax */ - } - - return cost; -} - -/* binary heap implementation of priority queue */ - -STATIC void -insert(l) - link *l; -{ register node *n; - - n = l->l_to; - if (n->n_flag & MAPPED) - die("insert mapped node"); - - Heap[n->n_tloc] = 0; - if (Heap[Nheap+1] != 0) - die("heap error in insert"); - if (Nheap++ == 0) { - Heap[1] = l; - n->n_tloc = 1; - return; - } - if (Vflag && Nheap > Heaphighwater) - Heaphighwater = Nheap; /* diagnostics */ - - /* insert at the end. caller must heapup(l). */ - Heap[Nheap] = l; - n->n_tloc = Nheap; -} - -/* - * "percolate" up the heap by exchanging with the parent. as in - * min_node(), give tiebreaker() a chance to produce better, stable - * routes by moving nets and domains close to the root, nets closer - * than domains. - * - * i know this seems obscure, but it's harmless and cheap. trust me. - */ -STATIC void -heapup(l) - link *l; -{ register long cindx, pindx; /* child, parent indices */ - register Cost cost; - register node *child, *parent; - - child = l->l_to; - - cost = child->n_cost; - for (cindx = child->n_tloc; cindx > 1; cindx = pindx) { - pindx = cindx / 2; - if (Heap[pindx] == 0) /* sanity check */ - die("impossible error in heapup"); - parent = Heap[pindx]->l_to; - if (cost > parent->n_cost) - return; - - /* net/domain heuristic */ - if (cost == parent->n_cost) { - if (!ISANET(child)) - return; - if (!ISADOMAIN(parent)) - return; - if (ISADOMAIN(child)) - return; - } - heapswap(cindx, pindx); - } -} - -/* extract min (== Heap[1]) from heap */ -STATIC link * -min_node() -{ link *rval, *lastlink; - register link **rheap; - - if (Nheap == 0) - return 0; - - rheap = Heap; /* in register -- heavily used */ - rval = rheap[1]; /* return this one */ - - /* move last entry into root and reheap */ - lastlink = rheap[Nheap]; - rheap[Nheap] = 0; - - if (--Nheap) { - rheap[1] = lastlink; - lastlink->l_to->n_tloc = 1; - heapdown(lastlink); /* restore heap property */ - } - - return rval; -} - -/* - * swap Heap[i] with smaller child, iteratively down the tree. - * - * given the opportunity, attempt to place nets and domains - * near the root. this helps tiebreaker() shun domain routes. - */ - -STATIC void -heapdown(l) - link *l; -{ register long pindx, cindx; - register link **rheap = Heap; /* in register -- heavily used */ - node *child, *rchild, *parent; - - pindx = l->l_to->n_tloc; - parent = rheap[pindx]->l_to; /* invariant */ - for ( ; (cindx = pindx * 2) <= Nheap; pindx = cindx) { - /* pick lhs or rhs child */ - child = rheap[cindx]->l_to; - if (cindx < Nheap) { - /* compare with rhs child */ - rchild = rheap[cindx+1]->l_to; - /* - * use rhs child if smaller than lhs child. - * if equal, use rhs if net or domain. - */ - if (child->n_cost > rchild->n_cost) { - child = rchild; - cindx++; - } else if (child->n_cost == rchild->n_cost) - if (ISANET(rchild)) { - child = rchild; - cindx++; - } - } - - /* child is the candidate for swapping */ - if (parent->n_cost < child->n_cost) - break; - - /* - * heuristics: - * move nets/domains up - * move nets above domains - */ - if (parent->n_cost == child->n_cost) { - if (!ISANET(child)) - break; - if (ISANET(parent) && ISADOMAIN(child)) - break; - } - - heapswap(pindx, cindx); - } -} - -/* exchange Heap[i] and Heap[j] pointers */ -STATIC void -heapswap(i, j) - long i, j; -{ register link *temp, **rheap; - - rheap = Heap; /* heavily used -- put in register */ - temp = rheap[i]; - rheap[i] = rheap[j]; - rheap[j] = temp; - rheap[j]->l_to->n_tloc = j; - rheap[i]->l_to->n_tloc = i; -} - -/* return 1 if n is already de-hashed (n_tloc < Hashpart), 0 o.w. */ -STATIC int -dehash(n) - register node *n; -{ - if (n->n_tloc < Hashpart) - return 1; - - /* swap with entry in Table[Hashpart] */ - Table[Hashpart]->n_tloc = n->n_tloc; - Table[n->n_tloc] = Table[Hashpart]; - Table[Hashpart] = n; - - n->n_tloc = Hashpart++; - return 0; -} - -/* - * everything reachable has been mapped. what to do about any - * unreachable hosts? the sensible thing to do is to dump them on - * stderr and be done with it. unfortunately, there are hundreds of - * such hosts in the usenet maps. so we take the low road: for each - * unreachable host, we add a back link from its cheapest mapped child, - * in the faint that a reverse path works. - * - * beats me why people want their error output in their map databases. - */ -STATIC void -backlinks() -{ register link *l; - register node *n, *child; - node *nomap; - long i; - - /* hosts from Hashpart to Tabsize are unreachable */ - for (i = Hashpart; i < Tabsize; i++) { - nomap = Table[i]; - /* if a copy has been mapped, we're ok */ - if (nomap->n_copy != nomap) { - dehash(nomap); - Table[nomap->n_tloc] = 0; - nomap->n_tloc = 0; - continue; - } - - /* TODO: simplify this */ - /* add back link from minimal cost child */ - child = 0; - for (l = nomap->n_link; l; l = l->l_next) { - n = l->l_to; - /* never ever ever crawl out of a domain */ - if (ISADOMAIN(n)) - continue; - if ((n = mappedcopy(n)) == 0) - continue; - if (child == 0) { - child = n; - continue; - } - if (n->n_cost > child->n_cost) - continue; - if (n->n_cost == child->n_cost) { - nomap->n_parent = child; /* for tiebreaker */ - if (tiebreaker(nomap, n)) - continue; - } - child = n; - } - if (child == 0) - continue; - (void) dehash(nomap); - l = addlink(child, nomap, INF, DEFNET, DEFDIR); /* INF cost */ - nomap->n_parent = child; - nomap->n_cost = costof(child, l); - insert(l); - heapup(l); - if (Vflag > 1) - fprintf(stderr, "backlink: %s <- %s\n", nomap->n_name, child->n_name); - } - vprintf(stderr, "%d backlinks\n", Nheap); -} - -/* find a mapped copy of n if it exists */ -STATIC node * -mappedcopy(n) - register node *n; -{ register node *ncp; - - if (n->n_flag & MAPPED) - return n; - for (ncp = n->n_copy; ncp != n; ncp = ncp->n_copy) - if (ncp->n_flag & MAPPED) - return ncp; - return 0; -} - -/* - * l has just been added or changed in the heap, - * so reset the state bits for l->l_to. - */ -STATIC void -setheapbits(l) - register link *l; -{ register node *n; - register node *parent; - - n = l->l_to; - parent = n->n_parent; - n->n_flag &= ~(NALIAS|HASLEFT|HASRIGHT); /* reset */ - - /* record whether link is an alias */ - if (l->l_flag & LALIAS) { - n->n_flag |= NALIAS; - /* TERMINALity is inherited by the alias */ - if (parent->n_flag & NTERMINAL) - n->n_flag |= NTERMINAL; - } - - /* set left/right bits */ - if (NETDIR(l) == LLEFT || (parent->n_flag & HASLEFT)) - n->n_flag |= HASLEFT; - if (NETDIR(l) == LRIGHT || (parent->n_flag & HASRIGHT)) - n->n_flag |= HASRIGHT; -} - -STATIC void -mtracereport(from, l, excuse) - node *from; - link *l; - char *excuse; -{ node *to = l->l_to; - - fprintf(stderr, "%-16s ", excuse); - trprint(stderr, from); - fputs(" -> ", stderr); - trprint(stderr, to); - fprintf(stderr, " (%ld, %ld, %ld) ", from->n_cost, l->l_cost, to->n_cost); - if (to->n_parent) { - trprint(stderr, to->n_parent); - fprintf(stderr, " (%ld)", to->n_parent->n_cost); - } - putc('\n', stderr); -} - -STATIC void -otracereport(n) - node *n; -{ - if (n->n_parent) - trprint(stderr, n->n_parent); - else - fputs("[root]", stderr); - fputs(" -> ", stderr); - trprint(stderr, n); - fputs(" mapped\n", stderr); -} - -#if 0 -/* extremely time consuming, exhaustive check of heap sanity. */ -chkheap(i) -{ int lhs, rhs; - - lhs = i * 2; - rhs = lhs + 1; - - if (lhs <= Nheap) { - if (Heap[i]->l_to->n_cost > Heap[lhs]->l_to->n_cost) - die("chkheap failure on lhs"); - chkheap(lhs); - } - if (rhs <= Nheap) { - if (Heap[i]->l_to->n_cost > Heap[rhs]->l_to->n_cost) - die("chkheap failure on rhs"); - chkheap(rhs); - } -#if 00 - /* this hasn't been used for years */ - for (i = 1; i < Nheap; i++) { - link *l; - - vprintf(stderr, "%5d %-16s", i, Heap[i]->l_to->n_name); - if ((l = Heap[i]->l_to->n_link) != 0) do { - vprintf(stderr, "%-16s", l->l_to->n_name); - } while ((l = l->l_next) != 0); - vprintf(stderr, "\n"); - } - for (i = Hashpart; i < Tabsize; i++) { - link *l; - node *n; - - vprintf(stderr, "%5d %-16s", i, Table[i]->n_name); - if ((l = Table[i]->n_link) != 0) do { - vprintf(stderr, "%-16s", l->l_to->n_name); - } while ((l = l->l_next) != 0); - vprintf(stderr, "\n"); - } -#endif /*00*/ - -} -#endif /*0*/ - -/* this isn't much use */ -#if 0 -STATIC int -chkgap() -{ static int gap = -1; - int newgap; - - newgap = Hashpart - Nheap; - if (gap == -1 || newgap < gap) - gap = newgap; - return gap; -} -#endif /*0*/ //GO.SYSIN DD mapit.c echo mapaux.c 1>&2 sed 's/^-//' >mapaux.c <<'//GO.SYSIN DD mapaux.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)mapaux.c 9.4 89/03/01"; -#endif /* lint */ - -#include "def.h" - -/* imports */ -extern long Nheap, Hashpart, Tabsize, NumNcopy, Nlink, NumLcopy; -extern node **Table, *Home; -extern char *Graphout, *Linkout, *Netchars, **Argv; -extern int Vflag; -extern void freelink(), die(); -extern long pack(); -extern link *newlink(); -extern node *newnode(); -extern char *strsave(); -extern int strcmp(), strlen(); - -/* exports */ -extern long pack(); -extern void resetnodes(), dumpgraph(), showlinks(), terminalnet(); -extern int tiebreaker(); -extern node *ncopy(); - -/* privates */ -static FILE *Gstream; /* for dumping graph */ -STATIC void dumpnode(), untangle(), dfs(); -STATIC int height(); -STATIC link *lcopy(); - - -/* - * slide everything from Table[low] to Table[high] - * up toward the high end. make room! make room! - */ -long -pack(low, high) - long low, high; -{ long hole, next; - - /* find first "hole " */ - for (hole = high; hole >= low && Table[hole] != 0; --hole) - ; - - /* repeatedly move next filled entry into last hole */ - for (next = hole - 1; next >= low; --next) { - if (Table[next] != 0) { - Table[hole] = Table[next]; - Table[hole]->n_tloc = hole; - Table[next] = 0; - while (Table[--hole] != 0) /* find next hole */ - ; - } - } - return hole + 1; -} - -void -resetnodes() -{ register long i; - register node *n; - - for (i = Hashpart; i < Tabsize; i++) - if ((n = Table[i]) != 0) { - n->n_cost = (Cost) 0; - n->n_flag &= ~(NALIAS|ATSIGN|MAPPED|HASLEFT|HASRIGHT|NTERMINAL); - n->n_copy = n; - } - - Home->n_cost = (Cost) 0; - Home->n_flag &= ~(NALIAS|ATSIGN|MAPPED|HASLEFT|HASRIGHT|NTERMINAL); - Home->n_copy = Home; -} - -void -dumpgraph() -{ register long i; - register node *n; - - if ((Gstream = fopen(Graphout, "w")) == NULL) { - fprintf(stderr, "%s: ", Argv[0]); - perror(Graphout); - return; - } - - untangle(); /* untangle net cycles for proper output */ - - for (i = Hashpart; i < Tabsize; i++) { - n = Table[i]; - if (n == 0) - continue; /* impossible, but ... */ - /* a minor optimization ... */ - if (n->n_link == 0) - continue; - /* pathparse doesn't need these */ - if (n->n_flag & NNET) - continue; - dumpnode(n); - } -} - -STATIC void -dumpnode(from) - register node *from; -{ register node *to; - register link *l; - link *lnet = 0, *ll, *lnext; - - for (l = from->n_link ; l; l = l->l_next) { - to = l->l_to; - if (from == to) - continue; /* oops -- it's me! */ - - if ((to->n_flag & NNET) == 0) { - /* host -> host -- print host>host */ - if (l->l_cost == INF) - continue; /* phoney link */ - fputs(from->n_name, Gstream); - putc('>', Gstream); - fputs(to->n_name, Gstream); - putc('\n', Gstream); - } else { - /* - * host -> net -- just cache it for now. - * first check for dups. (quadratic, but - * n is small here.) - */ - while (to->n_root && to != to->n_root) - to = to->n_root; - for (ll = lnet; ll; ll = ll->l_next) - if (strcmp(ll->l_to->n_name, to->n_name) == 0) - break; - if (ll) - continue; /* dup */ - ll = newlink(); - ll->l_next = lnet; - ll->l_to = to; - lnet = ll; - } - } - - /* dump nets */ - if (lnet) { - /* nets -- print host@\tnet,net, ... */ - fputs(from->n_name, Gstream); - putc('@', Gstream); - putc('\t', Gstream); - for (ll = lnet; ll; ll = lnext) { - lnext = ll->l_next; - fputs(ll->l_to->n_name, Gstream); - if (lnext) - fputc(',', Gstream); - freelink(ll); - } - putc('\n', Gstream); - } -} - -/* - * remove cycles in net definitions. - * - * depth-first search - * - * for each net, run dfs on its neighbors (nets only). if we return to - * a visited node, that's a net cycle. mark the cycle with a pointer - * in the n_root field (which gets us closer to the root of this - * portion of the dfs tree). - */ -STATIC void -untangle() -{ register long i; - register node *n; - - for (i = Hashpart; i < Tabsize; i++) { - n = Table[i]; - if (n == 0 || (n->n_flag & NNET) == 0 || n->n_root) - continue; - dfs(n); - } -} - -STATIC void -dfs(n) - register node *n; -{ register link *l; - register node *next; - - n->n_flag |= INDFS; - n->n_root = n; - for (l = n->n_link; l; l = l->l_next) { - next = l->l_to; - if ((next->n_flag & NNET) == 0) - continue; - if ((next->n_flag & INDFS) == 0) { - dfs(next); - if (next->n_root != next) - n->n_root = next->n_root; - } else - n->n_root = next->n_root; - } - n->n_flag &= ~INDFS; -} - -void -showlinks() -{ register link *l; - register node *n; - register long i; - FILE *estream; - - if ((estream = fopen(Linkout, "w")) == 0) - return; - - for (i = Hashpart; i < Tabsize; i++) { - n = Table[i]; - if (n == 0 || n->n_link == 0) - continue; - for (l = n->n_link; l; l = l->l_next) { - fputs(n->n_name, estream); - putc('\t', estream); - if (NETDIR(l) == LRIGHT) - putc(NETCHAR(l), estream); - fputs(l->l_to->n_name, estream); - if (NETDIR(l) == LLEFT) - putc(NETCHAR(l), estream); - fprintf(estream, "(%d)\n", l->l_cost); - } - } - (void) fclose(estream); -} - -/* - * n is node in heap, newp is candidate for new parent. - * choose between newp and n->n_parent for parent. - * return 0 to use newp, non-zero o.w. - */ -#define NEWP 0 -#define OLDP 1 -int -tiebreaker(n, newp) - node *n; - register node *newp; -{ register char *opname, *npname, *name; - register node *oldp; - int metric; - - oldp = n->n_parent; - - /* given the choice, avoid gatewayed nets */ - if (GATEWAYED(newp) && !GATEWAYED(oldp)) - return OLDP; - if (!GATEWAYED(newp) && GATEWAYED(oldp)) - return NEWP; - - /* look at real parents, not nets */ - while ((oldp->n_flag & NNET) && oldp->n_parent) - oldp = oldp->n_parent; - while ((newp->n_flag & NNET) && newp->n_parent) - newp = newp->n_parent; - - /* use fewer hops, if possible */ - metric = height(oldp) - height(newp); - if (metric < 0) - return OLDP; - if (metric > 0) - return NEWP; - - /* - * compare names - */ - opname = oldp->n_name; - npname = newp->n_name; - name = n->n_name; - - /* use longest common prefix with parent */ - while (*opname == *name && *npname == *name && *name) { - opname++; - npname++; - name++; - } - if (*opname == *name) - return OLDP; - if (*npname == *name) - return NEWP; - - /* use shorter host name */ - metric = strlen(opname) - strlen(npname); - if (metric < 0) - return OLDP; - if (metric > 0) - return NEWP; - - /* use larger lexicographically */ - metric = strcmp(opname, npname); - if (metric < 0) - return NEWP; - return OLDP; -} - -STATIC int -height(n) - register node *n; -{ register int i = 0; - - if (n == 0) - return 0; - while ((n = n->n_parent) != 0) - if (ISADOMAIN(n) || !(n->n_flag & NNET)) - i++; - return i; -} - -/* - * return a copy of n ( == l->l_to). we rely on n and its copy - * pointing to the same name string, which is kludgey, but works - * because the name is non-volatile. - */ - -#define REUSABLE(n, l) (((n)->n_flag & NTERMINAL) == 0 \ - && ((n)->n_copy->n_flag & NTERMINAL) \ - && !((n)->n_copy->n_flag & NALIAS) \ - && !((l)->l_flag & LALIAS)) -node * -ncopy(parent, l) - register node *parent; - register link *l; -{ register node *n, *ncp; - -#ifdef DEBUG - if (Vflag > 1) - vprintf(stderr, "<%s> <- %s\n", l->l_to->n_name, parent->n_name); -#endif - n = l->l_to; - if (REUSABLE(n, l)) { - Nlink++; - return n->n_copy; /* re-use */ - } - NumNcopy++; - l->l_to = ncp = newnode(); - ncp->n_name = n->n_name; /* nonvolatile */ - ncp->n_tloc = --Hashpart; /* better not be > 20% of total ... */ - if (Hashpart == Nheap) - die("too many terminal links"); - Table[Hashpart] = ncp; - ncp->n_copy = n->n_copy; /* circular list */ - n->n_copy = ncp; - ncp->n_link = lcopy(parent, n); - ncp->n_flag = (n->n_flag & ~(NALIAS|ATSIGN|MAPPED|HASLEFT|HASRIGHT)) | NTERMINAL; - return ncp; -} - -/* - * copy l, but don't include any links to parent. - * - * this is a little messier than it should be, because - * of the funny test for ancestry, and because it wants - * to be recursive, but the recursion might be very deep - * (for a long link list), so it's done iteratively. - */ -STATIC link * -lcopy(parent, n) - register node *parent, *n; -{ register link *l, *lcp; - link *first = 0, *last = 0; - - for (l = n->n_link; l != 0; l = l->l_next) { - /* avoid vestigial descendants */ - if ((l->l_to->n_flag & MAPPED) != 0 - || ALTEREGO(l->l_to, parent)) - continue; -#ifdef DEBUG - if (Vflag > 1) - vprintf(stderr, "\t-> %s\n", l->l_to->n_name); -#endif - NumLcopy++; - lcp = newlink(); - *lcp = *l; /* struct copy */ - lcp->l_flag &= ~LTREE; - if (ISANET(n)) - lcp->l_flag |= LTERMINAL; - - if (first == 0) { - first = last = lcp; - } else { - last->l_next = lcp; - last = lcp; - } - } - if (last) - last->l_next = 0; - return first; -} //GO.SYSIN DD mapaux.c echo mem.c 1>&2 sed 's/^-//' >mem.c <<'//GO.SYSIN DD mem.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)mem.c 9.2 88/06/10"; -#endif - -#include "def.h" - -/* exports */ -long Ncount; -extern void freelink(), wasted(), freetable(); -extern long allocation(); - -/* imports */ -extern char *Netchars; -extern int Vflag; -extern char *sbrk(); -extern void die(); -extern int strlen(); - -/* privates */ -STATIC void nomem(); -static link *Lcache; -static unsigned int Memwaste; - -link * -newlink() -{ register link *rval; - - if (Lcache) { - rval = Lcache; - Lcache = Lcache->l_next; - strclear((char *) rval, sizeof(link)); - } else if ((rval = (link * ) calloc(1, sizeof(link))) == 0) - nomem(); - return rval; -} - -/* caution: this destroys the contents of l_next */ -void -freelink(l) - link *l; -{ - l->l_next = Lcache; - Lcache = l; -} - -node * -newnode() -{ register node *rval; - - if ((rval = (node * ) calloc(1, sizeof(node))) == 0) - nomem(); - Ncount++; - return rval; -} - -char * -strsave(s) - char *s; -{ register char *r; - - if ((r = malloc((unsigned) strlen(s) + 1)) == 0) - nomem(); - (void) strcpy(r, s); - return r; -} - -#ifndef strclear -void -strclear(str, len) - register char *str; - register long len; -{ - while (--len >= 0) - *str++ = 0; -} -#endif /*strclear*/ - -node ** -newtable(size) - long size; -{ register node **rval; - - if ((rval = (node **) calloc(1, (unsigned int) size * sizeof(node *))) == 0) - nomem(); - return rval; -} - -void -freetable(t, size) - node **t; - long size; -{ -#ifdef MYMALLOC - extern void addtoheap(); - - addtoheap((char *) t, size * sizeof(node *)); -#else - free((char *) t); -#endif -} - -STATIC void -nomem() -{ - static char epitaph[128]; - - sprintf(epitaph, "out of memory (%ldk allocated)", allocation()); - die(epitaph); -} - -/* data space allocation -- main sets `dataspace' very early */ -long -allocation() -{ - static char *dataspace; - long rval; - - if (dataspace == 0) { /* first time */ - dataspace = sbrk(0); /* &end? */ - return 0; - } - rval = (sbrk(0) - dataspace)/1024; - if (rval < 0) /* funny architecture? */ - rval = -rval; - return rval; -} - -/* how much memory has been wasted? */ -void -wasted() -{ - if (Memwaste == 0) - return; - vprintf(stderr, "memory allocator wasted %ld bytes\n", Memwaste); -} - -#ifdef MYMALLOC - -/* use c library malloc/calloc here, and here only */ -#undef malloc -#undef calloc - -/* imports */ -extern char *malloc(), *calloc(); - -/* private */ -STATIC int align(); - -/* allocate in MBUFSIZ chunks. 4k works ok (less 16 for malloc quirks). */ -#define MBUFSIZ (4 * 1024 - 16) - -/* - * mess with ALIGN at your peril. longword (== 0 mod 4) - * alignment seems to work everywhere. - */ - -#define ALIGN 2 - -typedef struct heap heap; -struct heap { - heap *h_next; - long h_size; -}; - -static heap *Mheap; /* not to be confused with a priority queue */ - -STATIC void -addtoheap(p, size) - char *p; - long size; -{ int adjustment; - heap *pheap; - - /* p is aligned, but it doesn't hurt to check */ - adjustment = align(p); - p += adjustment; - size -= adjustment; - - if (size < 1024) - return; /* can't happen */ - pheap = (heap *) p; /* pheap is shorthand */ - pheap->h_next = Mheap; - pheap->h_size = size; - Mheap = pheap; -} - -/* - * buffered malloc() - * returns space initialized to 0. calloc isn't used, since - * strclear can be faster. - * - * free is ignored, except for very large objects, - * which are returned to the heap with addtoheap(). - */ - -char * -mymalloc(n) - register unsigned int n; -{ static unsigned int size; /* how much do we have on hand? */ - static char *mstash; /* where is it? */ - register char *rval; - - if (n >= 1024) { /* for hash table */ - rval = malloc(n); /* aligned */ - if (rval) - strclear(rval, n); - return rval; - } - - n += align((char *) n); /* keep everything aligned */ - - if (n > size) { - Memwaste += size; /* toss the fragment */ - /* look in the heap */ - if (Mheap) { - mstash = (char *) Mheap; /* aligned */ - size = Mheap->h_size; - Mheap = Mheap->h_next; - } else { - mstash = malloc(MBUFSIZ); /* aligned */ - if (mstash == 0) { - size = 0; - return 0; - } - size = MBUFSIZ; - } - strclear(mstash, size); /* what if size > 2^16? */ - } - rval = mstash; - mstash += n; - size -= n; - return rval; -} - -/* - * what's the (mis-)alignment of n? return the complement of - * n mod 2^ALIGN - */ -STATIC int -align(n) - char *n; -{ register int abits; /* misalignment bits in n */ - - abits = (int) n & ~(0xff << ALIGN) & 0xff; - if (abits == 0) - return 0; - return (1 << ALIGN) - abits; -} - -#endif /*MYMALLOC*/ //GO.SYSIN DD mem.c echo printit.c 1>&2 sed 's/^-//' >printit.c <<'//GO.SYSIN DD printit.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)printit.c 9.4 89/02/07"; -#endif - -#include "def.h" - -/* - * print the routes by traversing the shortest path tree in preorder. - * use lots of char bufs -- profiling indicates this costs about 5 kbytes - */ - -/* exports */ -extern void printit(); - -/* imports */ -extern int Cflag, Vflag, Dflag, Fflag; -extern node *Home; -extern char *Netchars; -extern void die(); -extern int strlen(); - -/* privates */ -static link *Ancestor; /* for -f option */ -STATIC void preorder(), setpath(), printhost(), printdomain(); -STATIC char *hostpath(); -STATIC int printable(); - -/* in practice, even the longest paths are < 100 bytes */ -#define PATHSIZE 512 - -void -printit() -{ link *l; - char pbuf[PATHSIZE]; - - /* print home */ - if (Cflag) - printf("%ld\t", (long) Home->n_cost); - printf("%s\t%%s\n", Home->n_name); - - strcpy(pbuf, "%s"); - for (l = Home->n_link; l; l = l->l_next) { - if (l->l_flag & LTREE) { - l->l_flag &= ~LTREE; - Ancestor = l; - preorder(l, pbuf); - strcpy(pbuf, "%s"); - } - } - fflush(stdout); - fflush(stderr); -} - -/* - * preorder traversal of shortest path tree. - */ -STATIC void -preorder(l, ppath) - register link *l; - char *ppath; -{ register node *n; - node *ncp; /* circular copy list */ - Cost cost; - char npath[PATHSIZE]; - short p_dir; /* DIR bits of parent (for nets) */ - char p_op; /* net op of parent (for nets) */ - - setpath(l, ppath, npath); - n = l->l_to; - if (printable(n)) { - if (Fflag) - cost = Ancestor->l_to->n_cost; - else - cost = n->n_cost; - if (ISADOMAIN(n)) - printdomain(n, npath, cost); - else if (!(n->n_flag & NNET)) { - printhost(n, npath, cost); - } - n->n_flag |= PRINTED; - for (ncp = n->n_copy; ncp != n; ncp = ncp->n_copy) - ncp->n_flag |= PRINTED; - } - - /* prepare routing bits for domain members */ - p_dir = l->l_flag & LDIR; - p_op = l->l_netop; - - /* recursion */ - for (l = n->n_link; l; l = l->l_next) { - if (!(l->l_flag & LTREE)) - continue; - /* network member inherits the routing syntax of its gateway */ - if (ISANET(n)) { - l->l_flag = (l->l_flag & ~LDIR) | p_dir; - l->l_netop = p_op; - } - l->l_flag &= ~LTREE; - preorder(l, npath); - } -} - -STATIC int -printable(n) - register node *n; -{ node *ncp; - link *l; - - if (n->n_flag & PRINTED) - return 0; - - /* is there a cheaper copy? */ - for (ncp = n->n_copy; n != ncp; ncp = ncp->n_copy) { - if (!(ncp->n_flag & MAPPED)) - continue; /* unmapped copy */ - - if (n->n_cost > ncp->n_cost) - return 0; /* cheaper copy */ - - if (n->n_cost == ncp->n_cost && !(ncp->n_flag & NTERMINAL)) - return 0; /* synthetic copy */ - } - - /* will a domain route suffice? */ - if (Dflag && !ISANET(n) && ISADOMAIN(n->n_parent)) { - /* - * are there any interesting links? a link - * is interesting if it doesn't point back - * to the parent, and is not an alias. - */ - - /* check n */ - for (l = n->n_link; l; l = l->l_next) { - if (l->l_to == n->n_parent) - continue; - if (!(l->l_flag & LALIAS)) - return 1; - } - - /* check copies of n */ - for (ncp = n->n_copy; ncp != n; ncp = ncp->n_copy) { - for (l = ncp->n_link; l; l = l->l_next) { - if (l->l_to == n->n_parent) - continue; - if (!(l->l_flag & LALIAS)) - return 1; - } - } - - /* domain route suffices */ - return 0; - } - return 1; -} - -STATIC void -setpath(l, ppath, npath) - link *l; - register char *ppath, *npath; -{ register node *next, *parent; - char netchar; - - next = l->l_to; - parent = next->n_parent; - netchar = NETCHAR(l); - - /* for magic @->% conversion */ - if (parent->n_flag & ATSIGN) - next->n_flag |= ATSIGN; - - /* - * i've noticed that distant gateways to domains frequently get - * ...!gateway!user@dom.ain wrong. ...!gateway!user%dom.ain - * seems to work, so if next is a domain and the parent is - * not the local host, force a magic %->@ conversion. in this - * context, "parent" is the nearest ancestor that is not a net. - */ - while (ISANET(parent)) - parent = parent->n_parent; - if (ISADOMAIN(next) && parent != Home) - next->n_flag |= ATSIGN; - - /* - * special handling for nets (including domains) and aliases. - * part of the trick is to treat aliases to domains as 0 cost - * links. (the author believes they should be declared as such - * in the input, but the world disagrees). - */ - if (ISANET(next) || ((l->l_flag & LALIAS) && !ISADOMAIN(parent))) { - strcpy(npath, ppath); - return; - } - - if (netchar == '@') - if (next->n_flag & ATSIGN) - netchar = '%'; /* shazam? shaman? */ - else - next->n_flag |= ATSIGN; - - /* remainder should be a sprintf -- foo on '%' as an operator */ - for ( ; (*npath = *ppath) != 0; ppath++) { - if (*ppath == '%') { - switch(ppath[1]) { - case 's': - ppath++; - npath = hostpath(npath, l, netchar); - break; - - case '%': - *++npath = *++ppath; - npath++; - break; - - default: - die("unknown escape in setpath"); - break; - } - } else - npath++; - } -} - -STATIC char * -hostpath(path, l, netchar) - register char *path; - register link *l; - char netchar; -{ register node *prev; - - prev = l->l_to->n_parent; - if (NETDIR(l) == LLEFT) { - /* host!%s */ - strcpy(path, l->l_to->n_name); - path += strlen(path); - while (ISADOMAIN(prev)) { - strcpy(path, prev->n_name); - path += strlen(path); - prev = prev->n_parent; - } - *path++ = netchar; - if (netchar == '%') - *path++ = '%'; - *path++ = '%'; - *path++ = 's'; - } else { - /* %s@host */ - *path++ = '%'; - *path++ = 's'; - *path++ = netchar; - if (netchar == '%') - *path++ = '%'; - strcpy(path, l->l_to->n_name); - path += strlen(path); - while (ISADOMAIN(prev)) { - strcpy(path, prev->n_name); - path += strlen(path); - prev = prev->n_parent; - } - } - return path; -} - -STATIC void -printhost(n, path, cost) - register node *n; - char *path; - Cost cost; -{ - if (n->n_flag & PRINTED) - die("printhost called twice"); - n->n_flag |= PRINTED; - /* skip private hosts */ - if ((n->n_flag & ISPRIVATE) == 0) { - if (Cflag) - printf("%ld\t", (long) cost); - fputs(n->n_name, stdout); - putchar('\t'); - puts(path); - } -} - -STATIC void -printdomain(n, path, cost) - register node *n; - char *path; - Cost cost; -{ node *p; - - if (n->n_flag & PRINTED) - die("printdomain called twice"); - n->n_flag |= PRINTED; - - /* - * print a route for dom.ain if it is a top-level domain, unless - * it is private. - * - * print a route for sub.dom.ain only if all its ancestor dom.ains - * are private and sub.dom.ain is not private. - */ - if (!ISADOMAIN(n->n_parent)) { - /* top-level domain */ - if (n->n_flag & ISPRIVATE) { - vprintf(stderr, "ignoring private top-level domain %s\n", n->n_name); - return; - } - } else { - /* subdomain */ - for (p = n->n_parent; ISADOMAIN(p); p = p->n_parent) - if (!(p->n_flag & ISPRIVATE)) - return; - if (n->n_flag & ISPRIVATE) - return; - } - - /* print it (at last!) */ - if (Cflag) - printf("%ld\t", (long) cost); - do { - fputs(n->n_name, stdout); - n = n->n_parent; - } while (ISADOMAIN(n)); - putchar('\t'); - puts(path); -} //GO.SYSIN DD printit.c echo parse.y 1>&2 sed 's/^-//' >parse.y <<'//GO.SYSIN DD parse.y' -%{ -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)parse.y 9.10 88/09/07"; -#endif /* lint */ - -#include "def.h" - -/* scanner states (yylex, parse) */ -#define OTHER 0 -#define COSTING 1 -#define NEWLINE 2 -#define FILENAME 3 - -/* exports */ -long Tcount; -extern void yyerror(); - -/* imports */ -extern node *addnode(), *addprivate(); -extern void fixprivate(), alias(), deadlink(), deletelink(); -extern link *addlink(); -extern int strcmp(); -extern char *strsave(); -extern int optind; -extern char *Cfile, *Netchars, **Argv; -extern int Lineno, Argc; - -/* privates */ -STATIC void fixnet(), adjust(); -STATIC int yylex(), yywrap(), getword(); -static int Scanstate = NEWLINE; /* scanner (yylex) state */ - -/* flags for ys_flags */ -#define TERMINAL 1 -%} - -%union { - node *y_node; - Cost y_cost; - char y_net; - char *y_name; - struct { - node *ys_node; - Cost ys_cost; - short ys_flag; - char ys_net; - char ys_dir; - } y_s; -} - -%type <y_s> site asite -%type <y_node> links aliases plist network nlist host nhost -%type <y_node> usite delem dlist -%type <y_cost> cost cexpr - -%token <y_name> SITE HOST STRING -%token <y_cost> COST -%token <y_net> NET -%token EOL PRIVATE DEAD DELETE FILETOK ADJUST - -%left '+' '-' -%left '*' '/' - -%% -map : /* empty */ - | map EOL - | map links EOL - | map aliases EOL - | map network EOL - | map private EOL - | map dead EOL - | map delete EOL - | map file EOL - | map adjust EOL - | error EOL - ; - -links : host site cost { - struct link *l; - - l = addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir); - if (GATEWAYED($2.ys_node)) - l->l_flag |= LGATEWAY; - if ($2.ys_flag & TERMINAL) - l->l_flag |= LTERMINAL; - } - | links ',' site cost { - struct link *l; - - l = addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir); - if (GATEWAYED($3.ys_node)) - l->l_flag |= LGATEWAY; - if ($3.ys_flag & TERMINAL) - l->l_flag |= LTERMINAL; - } - | links ',' /* benign error */ - ; - -host : HOST {$$ = addnode($1);} - | PRIVATE {$$ = addnode("private");} - | DEAD {$$ = addnode("dead");} - | DELETE {$$ = addnode("delete");} - | FILETOK {$$ = addnode("file");} - | ADJUST {$$ = addnode("adjust");} - ; - -site : asite { - $$ = $1; - $$.ys_net = DEFNET; - $$.ys_dir = DEFDIR; - } - | NET asite { - $$ = $2; - $$.ys_net = $1; - $$.ys_dir = LRIGHT; - } - | asite NET { - $$ = $1; - $$.ys_net = $2; - $$.ys_dir = LLEFT; - } - ; - -asite : SITE { - $$.ys_node = addnode($1); - $$.ys_flag = 0; - } - | '<' SITE '>' { - Tcount++; - $$.ys_node = addnode($2); - $$.ys_flag = TERMINAL; - } - ; - -aliases : host '=' SITE {alias($1, addnode($3));} - | aliases ',' SITE {alias($1, addnode($3));} - | aliases ',' /* benign error */ - ; - -network : nhost '{' nlist '}' cost {fixnet($1, $3, $5, DEFNET, DEFDIR);} - | nhost NET '{' nlist '}' cost {fixnet($1, $4, $6, $2, LRIGHT);} - | nhost '{' nlist '}' NET cost {fixnet($1, $3, $6, $5, LLEFT);} - ; - -nhost : '=' {$$ = 0; /* anonymous net */} - | host '=' {$$ = $1; /* named net */} - ; - -nlist : SITE {$$ = addnode($1);} - | nlist ',' SITE { - node *n; - - n = addnode($3); - if (n->n_net == 0) { - n->n_net = $1; - $$ = n; - } - } - | nlist ',' /* benign error */ - ; - -private : PRIVATE '{' plist '}' /* list of privates */ - | PRIVATE '{' '}' {fixprivate();} /* end scope of privates */ - ; - -plist : SITE {addprivate($1)->n_flag |= ISPRIVATE;} - | plist ',' SITE {addprivate($3)->n_flag |= ISPRIVATE;} - | plist ',' /* benign error */ - ; - -dead : DEAD '{' dlist '}'; - -dlist : delem - | dlist ',' delem - | dlist ',' /* benign error */ - ; - -delem : SITE {deadlink(addnode($1), (node *) 0);} - | usite NET usite {deadlink($1, $3);} - ; - -usite : SITE {$$ = addnode($1);} ; /* necessary unit production */ - -delete : DELETE '{' dellist '}'; - -dellist : delelem - | dellist ',' delelem - | dellist ',' /* benign error */ - ; - -delelem : SITE { - node *n; - - n = addnode($1); - deletelink(n, (node *) 0); - n->n_flag |= ISPRIVATE; - } - | usite NET usite {deletelink($1, $3);} - ; - -file : FILETOK '{' {Scanstate = FILENAME;} STRING {Scanstate = OTHER;} '}' { - Lineno = 0; - Cfile = strsave($4); - } - -adjust : ADJUST '{' adjlist '}' ; - -adjlist : adjelem - | adjlist ',' adjelem - | adjlist ',' /* benign error */ - ; - -adjelem : usite cost {adjust($1, $2);} ; - -cost : {$$ = DEFCOST; /* empty -- cost is always optional */} - | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')' - {$$ = $3;} - ; - -cexpr : COST - | '-' cexpr {$$ = -$2;} - | '(' cexpr ')' {$$ = $2;} - | cexpr '+' cexpr {$$ = $1 + $3;} - | cexpr '-' cexpr {$$ = $1 - $3;} - | cexpr '*' cexpr {$$ = $1 * $3;} - | cexpr '/' cexpr { - if ($3 == 0) - yyerror("zero divisor\n"); - else - $$ = $1 / $3; - } - ; -%% - -void -#ifdef YYDEBUG -/*VARARGS1*/ -yyerror(fmt, arg) - char *fmt, *arg; -#else -yyerror(s) - char *s; -#endif -{ - /* a concession to bsd error(1) */ - fprintf(stderr, "\"%s\", ", Cfile); -#ifdef YYDEBUG - fprintf(stderr, "line %d: ", Lineno); - fprintf(stderr, fmt, arg); - putc('\n', stderr); -#else - fprintf(stderr, "line %d: %s\n", Lineno, s); -#endif -} - -/* - * patch in the costs of getting on/off the network. - * - * for each network member on netlist, add links: - * network -> member cost = 0; - * member -> network cost = parameter. - * - * if network and member both require gateways, assume network - * is a gateway to member (but not v.v., to avoid such travesties - * as topaz!seismo.css.gov.edu.rutgers). - * - * note that members can have varying costs to a network, by suitable - * multiple declarations. this is a feechur, albeit a useless one. - */ -STATIC void -fixnet(network, nlist, cost, netchar, netdir) - register node *network; - node *nlist; - Cost cost; - char netchar, netdir; -{ register node *member, *nextnet; - link *l; - static int netanon = 0; - char anon[25]; - - if (network == 0) { - sprintf(anon, "[unnamed net %d]", netanon++); - network = addnode(anon); - } - network->n_flag |= NNET; - - /* insert the links */ - for (member = nlist ; member; member = nextnet) { - - /* network -> member, cost is 0 */ - l = addlink(network, member, (Cost) 0, netchar, netdir); - if (GATEWAYED(network) && GATEWAYED(member)) - l->l_flag |= LGATEWAY; - - /* member -> network, cost is parameter */ - /* never ever ever crawl up from a domain*/ - if (!ISADOMAIN(network)) - (void) addlink(member, network, cost, netchar, netdir); - - nextnet = member->n_net; - member->n_net = 0; /* clear for later use */ - } -} - -/* scanner */ - -#define QUOTE '"' -#define STR_EQ(s1, s2) (s1[2] == s2[2] && strcmp(s1, s2) == 0) -#define NLRETURN() {Scanstate = NEWLINE; return EOL;} - -static struct ctable { - char *cname; - Cost cval; -} ctable[] = { - /* ordered by frequency of appearance in a "typical" dataset */ - {"DIRECT", 200}, - {"DEMAND", 300}, - {"DAILY", 5000}, - {"HOURLY", 500}, - {"DEDICATED", 100}, - {"EVENING", 2000}, - {"LOCAL", 25}, - {"LOW", 5}, /* baud rate, quality penalty */ - {"DEAD", MILLION}, - {"POLLED", 5000}, - {"WEEKLY", 30000}, - {"HIGH", -5}, /* baud rate, quality bonus */ - {"FAST", -80}, /* high speed (>= 9.6 kbps) modem */ - /* deprecated */ - {"ARPA", 100}, - {"DIALED", 300}, - {0, 0} -}; - -STATIC int -yylex() -{ static char retbuf[128]; /* for return to yacc part */ - register int c; - register char *buf = retbuf; - register struct ctable *ct; - register Cost cost; - char errbuf[128]; - - if (feof(stdin) && yywrap()) - return EOF; - - /* count lines, skip over space and comments */ - if ((c = getchar()) == EOF) - NLRETURN(); - -continuation: - while (c == ' ' || c == '\t') - if ((c = getchar()) == EOF) - NLRETURN(); - - if (c == '#') - while ((c = getchar()) != '\n') - if (c == EOF) - NLRETURN(); - - /* scan token */ - if (c == '\n') { - Lineno++; - if ((c = getchar()) != EOF) { - if (c == ' ' || c == '\t') - goto continuation; - ungetc(c, stdin); - } - NLRETURN(); - } - - switch(Scanstate) { - case COSTING: - if (isdigit(c)) { - cost = c - '0'; - for (c = getchar(); isdigit(c); c = getchar()) - cost = (cost * 10) + c - '0'; - ungetc(c, stdin); - yylval.y_cost = cost; - return COST; - } - - if (getword(buf, c) == 0) { - for (ct = ctable; ct->cname; ct++) - if (STR_EQ(buf, ct->cname)) { - yylval.y_cost = ct->cval; - return COST; - } - sprintf(errbuf, "unknown cost (%s), using default", buf); - yyerror(errbuf); - yylval.y_cost = DEFCOST; - return COST; - } - - return c; /* pass the buck */ - - case NEWLINE: - Scanstate = OTHER; - if (getword(buf, c) != 0) - return c; - /* - * special purpose tokens. - * - * the "switch" serves the dual-purpose of recognizing - * unquoted tokens only. - */ - switch(c) { - case 'p': - if (STR_EQ(buf, "private")) - return PRIVATE; - break; - case 'd': - if (STR_EQ(buf, "dead")) - return DEAD; - if (STR_EQ(buf, "delete")) - return DELETE; - break; - case 'f': - if (STR_EQ(buf, "file")) - return FILETOK; - break; - case 'a': - if (STR_EQ(buf, "adjust")) - return ADJUST; - break; - } - - yylval.y_name = buf; - return HOST; - - case FILENAME: - while (c != EOF && isprint(c)) { - if (c == ' ' || c == '\t' || c == '\n' || c == '}') - break; - *buf++ = c; - c = getchar(); - } - if (c != EOF) - ungetc(c, stdin); - *buf = 0; - yylval.y_name = retbuf; - return STRING; - } - - if (getword(buf, c) == 0) { - yylval.y_name = buf; - return SITE; - } - - if (index(Netchars, c)) { - yylval.y_net = c; - return NET; - } - - return c; -} - -/* - * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted - * string that contains no newline. return -1 on failure or EOF, 0 o.w. - */ -STATIC int -getword(str, c) - register char *str; - register int c; -{ - if (c == QUOTE) { - while ((c = getchar()) != QUOTE) { - if (c == '\n') { - yyerror("newline in quoted string\n"); - ungetc(c, stdin); - return -1; - } - if (c == EOF) { - yyerror("EOF in quoted string\n"); - return -1; - } - *str++ = c; - } - *str = 0; - return 0; - } - - /* host name must start with alphanumeric or `.' */ - if (!isalnum(c) && c != '.') - return -1; - -yymore: - do { - *str++ = c; - c = getchar(); - } while (isalnum(c) || c == '.' || c == '_'); - - if (c == '-' && Scanstate != COSTING) - goto yymore; - - ungetc(c, stdin); - *str = 0; - return 0; -} - -STATIC int -yywrap() -{ char errbuf[100]; - - fixprivate(); /* munge private host definitions */ - Lineno = 1; - while (optind < Argc) { - if (freopen((Cfile = Argv[optind++]), "r", stdin) != 0) - return 0; - sprintf(errbuf, "%s: %s", Argv[0], Cfile); - perror(errbuf); - } - freopen("/dev/null", "r", stdin); - return -1; -} - -STATIC void -adjust(n, cost) - node *n; - Cost cost; -{ link *l; - - n->n_cost += cost; /* cumulative */ - - /* hit existing links */ - for (l = n->n_link; l; l = l->l_next) { - if ((l->l_cost += cost) < 0) { - char buf[100]; - - l->l_flag |= LDEAD; - sprintf(buf, "link to %s deleted with negative cost", - l->l_to->n_name); - yyerror(buf); - } - } -} //GO.SYSIN DD parse.y echo makedb.c 1>&2 sed 's/^-//' >makedb.c <<'//GO.SYSIN DD makedb.c' -/* pathalias -- by steve bellovin, as told to peter honeyman */ -#ifndef lint -static char *sccsid = "@(#)makedb.c 9.1 87/10/04"; -#endif /* lint */ - -#include <stdio.h> -#include "config.h" - -typedef struct { - char *dptr; - int dsize; -} datum; - -char *Ofile = ALIASDB, *ProgName; - -#define USAGE "%s [-o dbmname] [-a] [file ...]\n" - -main(argc, argv) - char *argv[]; -{ char *ofptr; - int c, append = 0; - extern int optind; - extern char *optarg; - - ProgName = argv[0]; - while ((c = getopt(argc, argv, "o:a")) != EOF) - switch(c) { - case 'o': /* dbm output file */ - Ofile = optarg; - break; - - case 'a': /* append mode */ - append++; - break; - - default: - fprintf(stderr, USAGE, ProgName); - exit(1); - break; - } - - - if ((ofptr = rindex(Ofile, '/')) != 0) - ofptr++; - else - ofptr = Ofile; - if (strlen(ofptr) > 10) { - ofptr[10] = 0; - fprintf(stderr, "%s: using %s for dbm output\n", ProgName, Ofile); - } - - if (append == 0 && dbfile(Ofile) != 0) { - perror_(Ofile); - exit(1); - } - - if (dbminit(Ofile) < 0) { - perror_(Ofile); - exit(1); - } - - if (optind == argc) - makedb((char *) 0); - else for ( ; optind < argc; optind++) - makedb(argv[optind]); - exit(0); -} - -dbfile(dbf) - char *dbf; -{ - return (dbcreat(dbf, "dir") != 0 || dbcreat(dbf, "pag") != 0); -} - -dbcreat(dbf, suffix) - char *dbf, *suffix; -{ char buf[BUFSIZ]; - int fd; - - (void) sprintf(buf, "%s.%s", dbf, suffix); - if ((fd = creat(buf, 0666)) < 0) - return(-1); - (void) close(fd); - return(0); -} - - -makedb(ifile) - char *ifile; -{ char line[BUFSIZ]; - datum key, val; - - if (ifile && (freopen(ifile, "r", stdin) == NULL)) { - perror_(ifile); - return; - } - - /* - * keys and values are 0 terminated. this wastes time and (disk) space, - * but does lend simplicity and backwards compatibility. - */ - key.dptr = line; - while (fgets(line, sizeof(line), stdin) != NULL) { - char *op, *end; - - end = line + strlen(line); - end[-1] = 0; /* kill newline, stuff null terminator */ - op = index(line, '\t'); - if (op != 0) { - *op++ = 0; - key.dsize = op - line; /* 0 terminated */ - val.dptr = op; - val.dsize = end - op; /* 0 terminated */ - } else { - key.dsize = end - line; /* 0 terminated */ - val.dptr = "\0"; /* why must i do this? */ - val.dsize = 1; - } - if (store(key, val) < 0) - perror_(Ofile); - } -} - -perror_(str) - char *str; -{ - fprintf(stderr, "%s: ", ProgName); - perror(str); -} //GO.SYSIN DD makedb.c echo arpatxt.c 1>&2 sed 's/^-//' >arpatxt.c <<'//GO.SYSIN DD arpatxt.c' -#ifndef lint -static char *sccsid = "@(#)arpatxt.c 9.4 88/09/21"; -#endif - -/* - * convert hosts.txt into pathalias format. - * - * alias rule: "host.dom.ain,nickname.arpa,..." -> host = nickname, ... - */ - -/* remove the next line for standard or research unix */ -#define BSD - -#ifdef BSD -#define strchr index -#endif /* BSD */ - -#include <stdio.h> -#include <ctype.h> - -/* imports */ -extern char *re_comp(), *malloc(), *strchr(), *calloc(); -extern char *gets(), *strcpy(), *fgets(); -extern FILE *fopen(); - -typedef struct node node; - -struct node { - node *child; /* subdomain or member host */ - node *parent; /* parent domain */ - node *next; /* sibling in domain tree or host list */ - char *name; /* host name */ - node *alias; /* list of aliases */ - node *bucket; - node *gateway; - int flag; -}; - -node *Top; -int Atflag, Fflag, Iflag, Vflag; -char *DotArpa = ".ARPA"; -char Fname[256], *Fstart; - -node *newnode(), *find(); -char *strsave(), *lowercase(); -void crcinit(); -long fold(); -FILE *mkfile(); -int insert(); - -#define ISADOMAIN(n) ((n) && *((n)->name) == '.') - -/* for node.flag */ -#define COLLISION 1 - -/* for formatprint() */ -#define PRIVATE 0 -#define HOSTS 1 -#define SUBDOMAINS 2 - -/* for usage() */ -#define USAGE "usage: %s [-i@] [-g gateway] [-p privatefile] [-f | -d directory] [file ...]\n" - -main(argc, argv) - char **argv; -{ int c; - char *progname; - extern char *optarg; - extern int optind; - - if ((progname = strchr(argv[0], '/')) != 0) - progname++; - else - progname = argv[0]; - crcinit(); - - Top = newnode(); /* needed for adding gateways */ - while ((c = getopt(argc, argv, "d:fg:ip:v@")) != EOF) - switch(c) { - case 'd': - strcpy(Fname, optarg); - break; - case 'f': /* filter mode -- write on stdout */ - Fflag++; - break; - case 'g': - gateway(optarg); - break; - case 'i': - Iflag++; - break; - case 'p': - readprivates(optarg); - break; - case 'v': - Vflag++; - break; - case '@': - Atflag++; - break; - default: - usage(progname); - } - - if (Fflag && *Fname) - usage(progname); - if (Iflag) - (void) lowercase(DotArpa); - if (Top->gateway == 0) - fprintf(stderr, "%s: warning: no gateway to top level domains\n", progname); - - Fstart = Fname + strlen(Fname); - if (Fstart != Fname) { - *Fstart++ = '/'; - *Fstart = 0; - } - /* should do the mkdir here instead of the shell script ...*/ - - Top->name = "internet"; - if (optind == argc) - scan(); - else for ( ; optind < argc; optind++) { - if (freopen(argv[optind], "r", stdin) == 0) { - perror(argv[optind]); - continue; - } - scan(); - } - setuniqflag(Top); /* look for and mark collisions */ - hashanalyze(); /* check hash algorithm performance */ - merge(); /* make unique domain names */ - dump(Top); /* print */ - return 0; -} - -scan() -{ static first; - char buf0[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; - - if (first++ == 0) - (void) re_comp("^HOST.*SMTP"); - while (gets(buf0) != 0) { - if (re_exec(buf0) == 0) - continue; - if (sscanf(buf0, "HOST : %[^:] : %[^: ]", buf1, buf2) != 2) - continue; - if (Iflag) - (void) lowercase(buf2); - if (insert(buf2) != 0) - fprintf(stderr, "input error: %s\n", buf0); - } -} -/* - * format of private file: - * one per line, optionally followed by white space and comments - * line starting with # is comment - */ -readprivates(pfile) - char *pfile; -{ FILE *f; - node *n; - char buf[BUFSIZ], *bptr; - - if ((f = fopen(pfile, "r")) == 0) { - perror(pfile); - return; - } - while (fgets(buf, BUFSIZ, f) != 0) { - if (*buf == '#') - continue; - if ((bptr = strchr(buf, ' ')) != 0) - *bptr = 0; - if ((bptr = strchr(buf, '\t')) != 0) - *bptr = 0; - if (*buf == 0) - continue; - n = newnode(); - n->name = strsave(buf); - hash(n); - } - (void) fclose(f); -} -usage(progname) - char *progname; -{ - fprintf(stderr, USAGE, progname); - exit(1); -} - -dumpgateways(ndom, f) - node *ndom; - FILE *f; -{ node *n; - - for (n = ndom->gateway; n; n = n->next) { - fprintf(f, "%s ", n->name); - if (Atflag) - putc('@', f); - fprintf(f, "%s(%s)\t# gateway\n", ndom->name, - ndom == Top ? "DEDICATED" : "LOCAL"); - } -} - -gateway(buf) - char *buf; -{ node *n, *dom; - char *dot; - - dot = strchr(buf, '.'); - if (dot) { - dom = find(dot); - *dot = 0; - } else - dom = Top; - - n = newnode(); - n->name = strsave(buf); - n->next = dom->gateway; - dom->gateway = n; -} - -int -insert(buf) - char *buf; -{ char host[BUFSIZ], *hptr, *dot; - node *n; - - for (hptr = host; *hptr = *buf++; hptr++) - if (*hptr == ',') - break; - - if (*hptr == ',') - *hptr = 0; - else - buf = 0; /* no aliases */ - - if ((dot = strchr(host, '.')) == 0) - return 1; /* can't happen */ - - if (strcmp(dot, DotArpa) == 0) - buf = 0; /* no aliases */ - - n = find(dot); - *dot = 0; - - addchild(n, host, buf); - return 0; -} - -node * -find(domain) - char *domain; -{ char *dot; - node *parent, *child; - - if (domain == 0) - return Top; - if ((dot = strchr(domain+1, '.')) != 0) { - parent = find(dot); - *dot = 0; - } else - parent = Top; - - for (child = parent->child; child; child = child->next) - if (strcmp(domain, child->name) == 0) - break; - if (child == 0) { - child = newnode(); - child->next = parent->child; - parent->child = child; - child->parent = parent; - child->name = strsave(domain); - } - return child; -} - -node * -newnode() -{ - node *n; - - if ((n = (node *) calloc(1, sizeof(node))) == 0) - abort(); - return n; -} - -char * -strsave(buf) - char *buf; -{ char *mstr; - - if ((mstr = malloc(strlen(buf)+1)) == 0) - abort(); - strcpy(mstr, buf); - return mstr; -} - -addchild(n, host, aliases) - node *n; - char *host, *aliases; -{ node *child; - - /* check for dups? nah! */ - child = newnode(); - child->name = strsave(host); - child->parent = n; - child->next = n->child; - makealiases(child, aliases); - n->child = child; -} - -/* yer basic tree walk to make output */ -dump(n) - node *n; -{ node *child; - FILE *f; - int privates; - - /* sanity check */ - if (n != Top && ! ISADOMAIN(n)) - abort(); - - f = mkfile(n); /* prepare the output file */ - privates = domprint(n, f); /* print this domain */ - dumpgateways(n, f); /* print any gateways to this domain */ - if (privates || n == Top) - fputs("private {}\n", f); /* end scope of privates */ - if (Fflag) - putc('\n', f); - else - (void) fclose(f); - for (child = n->child; child; child = child->next) - if (child->child) - dump(child); -} - -qcmp(a, b) - node **a, **b; -{ - return strcmp((*a)->name, (*b)->name); -} - -domprint(n, f) - node *n; - FILE *f; -{ node *table[8191], *child, *alias; - char *cost = 0; - int nelem, i, privates = 0; - - /* - * dump private definitions. - * sort hosts and aliases for pretty output. - */ - if (n != Top) { - i = 0; - for (child = n->child; child; child = child->next) { - table[i++] = child; - for (alias = child->alias; alias; alias = alias->next) - table[i++] = alias; - } - - qsort((char *) table, i, sizeof(table[0]), qcmp); - privates = formatprint(f, table, i, PRIVATE, "private", cost); - } - - /* dump domains and aliases, sorted for pretty output */ - i = 0; - for (child = n->child; child; child = child->next) - table[i++] = child; - qsort((char *) table, i, sizeof(table[0]), qcmp); - - /* cost is DEDICATED for hosts in top-level domains, LOCAL o.w. */ - if (n->parent == Top && strchr(n->name + 1, '.') == 0) - cost = "DEDICATED"; - else - cost = "LOCAL"; - - (void) formatprint(f, table, i, HOSTS, n->name, cost); - (void) formatprint(f, table, i, SUBDOMAINS, n->name, "0"); - - /* dump aliases */ - nelem = i; - for (i = 0; i < nelem; i++) { - if ((alias = table[i]->alias) == 0) - continue; - fprintf(f, "%s = %s", table[i]->name, alias->name); - for (alias = alias->next; alias; alias = alias->next) - fprintf(f, ", %s", alias->name); - putc('\n', f); - } - return privates; -} - -int -formatprint(f, table, nelem, type, lhs, cost) - FILE *f; - node **table; - char *lhs, *cost; -{ int i, didprint; - char buf[128], *bptr; - - sprintf(buf, "%s%s{" /*}*/, lhs, type == PRIVATE ? " " : " = "); - bptr = buf + strlen(buf); - - didprint = 0; - for (i = 0; i < nelem; i++) { - if (type == PRIVATE && ! (table[i]->flag & COLLISION)) - continue; - else if (type == HOSTS && ISADOMAIN(table[i]) ) - continue; - else if (type == SUBDOMAINS && ! ISADOMAIN(table[i]) ) - continue; - - if ((bptr - buf) + strlen(table[i]->name) > 69) { - *bptr = 0; - fprintf(f, "%s\n ", buf); /* continuation */ - bptr = buf; - } - sprintf(bptr, "%s, ", table[i]->name); - bptr += strlen(bptr); - didprint++; - } - *bptr = 0; - - if (didprint) { - fprintf(f, /*{*/ "%s}", buf); - if (type != PRIVATE) - fprintf(f, "(%s)", cost); - putc('\n', f); - } - return didprint; -} - -FILE * -mkfile(n) - node *n; -{ node *parent; - char *bptr; - FILE *f; - - /* build up the domain name in Fname[] */ - bptr = Fstart; - if (n == Top) - strcpy(bptr, n->name); - else { - strcpy(bptr, n->name + 1); /* skip leading dot */ - bptr = bptr + strlen(bptr); - parent = n->parent; - while (ISADOMAIN(parent)) { - strcpy(bptr, parent->name); - bptr += strlen(bptr); - parent = parent->parent; - } - *bptr = 0; - } - - /* get a stream descriptor */ - if (Fflag) { - printf("# %s\n", Fstart); - f = stdout; - } else { -#ifndef BSD - Fstart[14] = 0; -#endif - if ((f = fopen(Fname, "w")) == 0) { - perror(Fname); - exit(1); - } - } - if (n == Top) - fprintf(f, "private {%s}\ndead {%s}\n", Top->name, Top->name); - return f; -} - -/* map to lower case in place. return parameter for convenience */ -char * -lowercase(buf) - char *buf; -{ char *str; - - for (str = buf ; *str; str++) - if (isupper(*str)) - *str -= 'A' - 'a'; - return buf; -} - -/* get the interesting aliases, attach to n->alias */ -makealiases(n, line) - node *n; - char *line; -{ char *next, *dot; - node *a; - - if (line == 0 || *line == 0) - return; - - for ( ; line; line = next) { - next = strchr(line, ','); - if (next) - *next++ = 0; - if ((dot = strchr(line, '.')) == 0) - continue; - if (strcmp(dot, DotArpa) != 0) - continue; - *dot = 0; - - if (strcmp(n->name, line) == 0) - continue; - - a = newnode(); - a->name = strsave(line); - a->next = n->alias; - n->alias = a; - } -} - -/* make unique domain names */ -merge() -{ register node *n; - - for (n = Top->child; n; n = n->next) - make_children_unique(n); -} - -/* - * another recursive tree walk, this time to make unique domain - * components. - * - * for domains like cc.umich.edu and cc.berkeley.edu, it's inaccurate - * to describe cc as a member of umich.edu or berkeley.edu. (i.e., the - * lousy scoping rules for privates don't permit a clean syntax.) so. - * - * to prevent confusion, tack on to any such domain name its parent domain - * and promote it in the tree. e.g., make cc.umich and cc.berkeley - * subdomains of edu. - */ - -make_children_unique(parent) - node *parent; -{ node *prev, *child, *next; - char buf[BUFSIZ]; - - prev = 0; - for (child = parent->child; child; child = next) { - next = child->next; - - /* skip hosts */ - if (!ISADOMAIN(child)) { - prev = child; - continue; - } - - /* - * promote non-unique domain, or any domain with a - * gateway. (the latter get promoted all the way to - * top-level.) - */ - if ((child->flag & COLLISION) == 0 && child->gateway == 0) { - /* - * uninteresting domain. make its children - * unique and bump prev. - */ - make_children_unique(child); - prev = child; - continue; - } - - /* - * gateway or dup domain name found. don't bump - * prev: this node is moving up the tree. - */ - - /* qualify child domain name */ - sprintf(buf, "%s%s", child->name, parent->name); - cfree(child->name); - child->name = strsave(buf); - - /* unlink child out of sibling chain */ - if (prev) - prev->next = child->next; - else - parent->child = child->next; - - /* link child in as peer of parent */ - child->next = parent->next; - parent->next = child; - child->parent = parent->parent; - - /* - * reset collision flag; may promote again on - * return to caller. - */ - child->flag &= ~COLLISION; - hash(child); - } -} - -/* another recursive tree walk, this time to set the COLLISION bit. */ -setuniqflag(n) - node *n; -{ node *child, *alias; - - /* mark this node in the hash table */ - hash(n); - /* mark the aliases of this node */ - for (alias = n->alias; alias; alias = alias->next) - hash(alias); - /* recursively mark this node's children */ - for (child = n->child; child; child = child->next) - setuniqflag(child); -} - -#define NHASH 8191 /* must be prime */ -node *Htable[NHASH]; /* hash table */ - -hash(n) - node *n; -{ node **bucket, *b; - - bucket = Htable + (fold(n->name) % NHASH); - for (b = *bucket; b; b = b->bucket) - if (strcmp(n->name, b->name) == 0) { - b->flag |= COLLISION; - n->flag |= COLLISION; - return; - } - - n->bucket = *bucket; - *bucket = n; -} - -/* stolen from pathalias:addnode.c, q.v. */ -#define POLY 0x48000000 /* 31-bit polynomial */ -long CrcTable[128]; - -void -crcinit() -{ register int i,j; - register long sum; - - for (i = 0; i < 128; i++) { - sum = 0; - for (j = 7-1; j >= 0; --j) - if (i & (1 << j)) - sum ^= POLY >> j; - CrcTable[i] = sum; - } -} - -long -fold(s) - register char *s; -{ register long sum = 0; - register int c; - - while (c = *s++) - sum = (sum >> 7) ^ CrcTable[(sum ^ c) & 0x7f]; - return sum; -} - -hashanalyze() -{ int nodecount = 0, maxlen = 0, len, i, probes = 0; - node *n; - - if (!Vflag) - return; - - for (i = 0; i < NHASH; i++) { - len = 0; - for (n = Htable[i]; n; n = n->bucket) { - len++; - probes += len; - } - nodecount += len; - if (len > maxlen) - maxlen = len; - } - fprintf(stderr, - "load = %2.2f, probes/access = %2.2f, %d nodes, max chain is %d\n", - (double) nodecount / (double) NHASH, - (double) probes / (double) nodecount, nodecount, maxlen); -} //GO.SYSIN DD arpatxt.c echo arpa-privates 1>&2 sed 's/^-//' >arpa-privates <<'//GO.SYSIN DD arpa-privates' -################################################################# -# arpa-privates file for arpatxt/pathalias # -# # -# updated from hosts.txt ver. 750 and the # -# UUCP Project map data as of 17-Jun-88 # -################################################################# -# "master" file is available for anonymous ftp at: # -# swan.ulowell.edu:~ftp/hosts/arpa-privates # -# citi.umich.edu:~ftp/pub/honey/arpa-privates # -# # -# Send updates to postmaster at one of above sites. # -################################################################# -# format: # -# host map.file (for registered UUCP hosts) # -# host [map.file] (for unregistered UUCP hosts) # -# Everything after white space is ignored, and is # -# primarily intended to keep the file easier to update. # -# Order does not matter, but case does. # -################################################################# -a usa.ca -aardvark usa.or -abbott usa.ca -ac1 [usa.ca] nsc -ac6 [usa.ca] cerebus, esl -achilles [att] -acorn gbr -adam swe -adams swe -admin usa.ca -alamo usa.tx -alex usa.va -alf [usa.az] ellymae -algedi [usa.wa] pilchuck -alien usa.ca -alpha usa.in -altair [usa.tx] juniper -amc usa.wa -amos [usa.ca] suntan -andy [att] -antares usa.nj -anubis usa.il -apollo usa.ma -aqua usa.ma -arc usa.ca -ares swe -argon usa.nj -argus usa.nj -ariadne grc -ariel [usa.oh] mtune-isn -aris grc -arthur [usa.mo] wuphys -asgard usa.or -astro [usa.tx] milano -athena [usa.ca] daisy -atlas [att] -att -b21 deu -bacchus usa.nc -bert usa.ca -bezier [usa.oh] bgsuvax -blue jpn -bluto [usa.tx] im4u -bobcat [usa.ca] vortex -boojum [att] -boole [att] -bosco [esp] -bounty [usa.az] ellymae -bourbaki usa.il -bridge [usa.il] richp1 -bugs [usa.ca] cuschico -bull usa.ca -cac usa.ma -cad dmk (ibt) -calico usa.ny -callisto usa.in -calvin [usa.ca] ucdavis -cantor [usa.il] gargoyle, luccpud -carl swe -carmel [usa.az] verde -carrara [usa.ma] talcott -casper usa.or -castor [att] -ccb [kor] kaist -ccd usa.fl (pd1) -ccs [usa.tx] convex -cerberus usa.ca -chaos usa.ok -cheetah usa.oh -chem usa.ca -cheops [usa.ca] esl -chip usa.ca -chiron usa.ny -chopin [att] -cims1 usa.ga -cip ita -circe [att] -clara usa.ny -clover usa.ca -cls [usa.nh] sii -clutx [usa.fl] gould -cmr usa.fl -cogito [att] -cognac usa.pa -colby usa.me -condor usa.ma -cookie usa.ne -coral usa.ca -cortex [usa.tx] CNLNET/soma -cottage gbr -crash usa.ca -cs1 usa.ca -csab [usa.va] xanth, [usa.il] uiucdcs -csc can.on -csd1 [usa.ny] cmcl2 -csd2 [usa.ny] cmcl2 -cssun [usa.ny] albanycs -csun1 usa.ga -csun2 usa.ga -cti usa.ca -curie usa.tx -cygnus usa.ny -dalek usa.ca -dali [esp] goya -darwin can.on -david usa.oh -dcn1 [usa.ca] scgvaxd -deimos [usa.oh] codas -delphi ita -deneb [can.bc] ubc-cs -descartes [usa.ca] nosc -devvax usa.ny (until Larry fixes news path on jpl-devvax) -dewey [usa.ca] hpda -dipl usa.ca -disc [usa.ca] ucdavis -dorothy usa.ca -draco [usa.tx] petro -ea usa.ok -eagle [usa.ca] ames -earth [att] -east fra -ecn nld -ed gbr -edam [att] -edith [usa.oh] mtune -eli usa.dc -else jpn -elvira [usa.dc] sundc -emily [usa.nj] althea -ems usa.mn -ernie usa.ca -escher usa.ca -etl [usa.va] potomac -eunice usa.fl -europa usa.ri -evans [usa.ca] ucbvax -eve [usa.ny] clara -ewok [usa.nc] suntri -falcon [usa.nc] suntri -faraday usa.ny -faust usa.ma -fenway usa.ga -fergvax [usa.ne] upba -fisher usa.nj -flight [usa.or] argent -fluke usa.wa -foobar usa.or -forest [usa.tx] hal6000 -forty2 che -fred usa.co -frisbee usa.co -frog usa.ma -gaia usa.co -galaxy usa.nj -gamma [usa.oh] codas -gandalf can.on -garfield can.nf -gateway [usa.ut] pedro -gemini usa.ca -george usa.tx -gilbert [usa.wa] pilchuck -gizmo [usa.ca] sun -godot usa.nc -godzilla [att] -golem usa.ca -gort [usa.ok] romed -gould usa.fl -granite [usa.nh] decvax -green [usa.md] jhunix -grendel [usa.oh] mtune -grinch usa.ca -groucho [att] -grumpy [usa.oh] codas -gull usa.tx -hal usa.oh -hamster [usa.ca] qantel -happy usa.ca -hawk [usa.ca] nosc -hector [att] -helios can.on -hermes [att] -hollywood [usa.ca] fortune -hottub usa.ca -hq sgp -hub [usa.ca] comdesign -hugo usa.va -hydra usa.nj -hydro [usa.ca] csustan -ibd [att] -ibis usa.tx -icarus [usa.ri] brunix -ice usa.wi -imagen usa.ca -indra [usa.oh] codas -intrepid usa.ar -io [usa.oh] mtune -ipac [usa.az] noao, [usa.ca] csula-ps -ircam fra -iris usa.ri -isi usa.ca -isis usa.co -island usa.ca -jack usa.ca -janus usa.ca -jhereg [usa.mn] bungia -juniper usa.tx -kaos usa.ma -kiwi bel -kontiki dmk -kronos grc -lafite [usa.nh] decvax -lassen usa.ca -laura deu -leg [fra] geocub -lego dmk -leopard [att] -lilac kor -linus usa.ma -lion [att] -lola [usa.oh] codas -lono usa.ca -lynx usa.ca -macom1 usa.md -magic [usa.ca] idi -manatee usa.fl -manta usa.pa -marge usa.ca -mars usa.nj -maui usa.va -max [att] -maxwell usa.mo -mcl can.sk -mcs usa.md -medusa usa.nj -megalon deu -mercury [usa.ma] interlan -merlin [usa.ma] masscomp -mickey usa.ca -mimas nld -minnie usa.co -miranda [usa.oh] mtune -mirage gbr -moe [usa.nv] jimi -mojave usa.ca -moses [usa.mi] umich -mouse usa.de -mozart usa.ny -mruxd [att] -ms can.on -mycroft [usa.ca] hplabs -myrddin [usa.ca] amdahl-bartender -netman [att] -newton [can.bc] ubc-cs -nexus usa.dc -nirvana usa.va -noether [usa.ny] mozart -nova usa.ok -oac [att] -nps [usa.il] cerl -nyquiest [att] -oahu [usa.nj] hjuxa -oak [usa.ct] clunker -oasis usa.ca (precautionary. llnl clashes with oasis.sait.ko.kr) -ocean [usa.ca] ucsbcsl -odin [att] -opus [att] -orbit usa.mn -orca [usa.az] ellymae -orcas usa.wa -oregon usa.or {believe it or not} -orion [att] -orville usa.ny -oscar [usa.oh] bcd-dyn -osiris usa.md -oz usa.wa -pallas usa.il -pandora [usa.ma] harv-net -pegasus [att] -percival usa.or -phobos usa.vt -phoebus gbr -phoenix [att] -physics [usa.ny] ccnysci -picasso [esp] goya -pilchuck usa.wa -pioneer usa.md -pixar usa.ca -plasma usa.ca -plato usa.ca -pluto usa.ny -pokey [usa.va] men2a -polaris [usa.wa] camco -pollux usa.tx -postel nld -presto usa.md -priam [che] cernvax -prime usa.ma -prism usa.nj -prodigal usa.pa -prometheus usa.md -psc usa.md -psych [aus] -psyche usa.nc -puppy usa.ny -qat [usa.tx] techsup -quark [usa.ca] csuchico -ra [can.bc] ubc-cs -rainier swe -ralph usa.la -rdm usa.ga -reason usa.ny -rebel usa.ga -red jpn -redwood [usa.ca] amdcad -ridge usa.ca -robin [usa.oh] bgsuvax [usa.ma] linus -rodan usa.or -rome usa.ok -rosetta [usa.tx] rice -rover [usa.az] ellymae -rsch [usa.ma] harvard -sable [usa.ca] pyramid -sabre [usa.oh] codas -sal swe -sam usa.il -sandy [usa.tx] woton -sas [usa.nc] rti -saturn [kor] ketri -scarecrow [usa.pa] lehi3b15 -scooter usa.ca -select nld -service gbr -shamash usa.mn -shaw [att] -shockeye usa.pa -shrike [usa.tx] MBIRNET -shrimp usa.tx -sierra usa.ca -simon usa.il -sirius [usa.nh] dartvax -smith [can.ab] edm -snark usa.pa -snucom kor -sol usa.nh -solar usa.nm -soleil usa.nj -spam usa.nj -sparky [usa.oh] codas -sphinx usa.il -spike usa.la -spock usa.ct -sri aus.qld -ssi usa.wi -star [usa.oh] codas -stars [can.ns] dalcs -stuart [usa.md] prometheus -stymie [usa.ma] harvard -suna [usa.mn] mscunx -sunburn usa.az -sunrise usa.nj -sunspot usa.nm -suntan usa.ca -sunup usa.wa -super usa.md -svc [usa.md] epiwrl -swamp [usa.ca] amdahl -swan usa.tx -taurus isr -te gbr -terminus [att] -thermo [usa.nv] stride1 -thor dmk -thunder can.on -tiger usa.nj -tinman usa.ca -titan usa.ca -trantor usa.ca -tut fin -ubvax usa.ca -unh usa.nh -unix usa.wa -usafa [usa.co] winfree, [usa.fl] gould, [usa.nh] trixie -valhalla [usa.mi] edsr -vax2 [usa.md] elsie -vector usa.tx -vice [usa.or] enky, budda, loop -video [att] -vilya [att] -viper [usa.mn] bungia, mmm, pwcs, quest -vista usa.ca -vlsi1 [usa.ut] byuopus -vlsi2 [usa.ut] byuopus -vlsi3 [usa.ut] byuopus -volt usa.ca -voodoo usa.wa -wang usa.ma -wayback [att] -wombat usa.ca -wotan usa.ca -xyzzy usa.nc -yoda usa.co (UCARNET) -yogi [usa.nj] bellcore-micom, pyrnj -z usa.ca -zap can.qc -zaphod can.sk -zeta [usa.md] cp1 -zeus can.bc -zip usa.oh -zorac can.on //GO.SYSIN DD arpa-privates echo make.honey 1>&2 sed 's/^-//' >make.honey <<'//GO.SYSIN DD make.honey' -#!/bin/make -f -# pathalias -- by steve bellovin, as told to peter honeyman - -### configuration section -### -# if you can't or don't intend to use dbm files, -# don't bother with DBM or makedb -DBM = -ldbm -# or if you roll your own ... -# DBM = dbm.o -### -# where is getopt (if not in the c library)? -# GETOPT = -lgetopt -### end of configuration section - -CC = cc -g -CFLAGS = -DDEBUG -LDFLAGS = -YFLAGS = -dD -YYDEBUG=0 - -OBJ = addlink.o addnode.o local.o main.o mapit.o mapaux.o mem.o parse.o printit.o -OFILES = addlink.O addnode.O local.O main.O mapit.O mapaux.O mem.O parse.O printit.O -HDRS = def.h config.h -CSRC = addlink.c addnode.c local.c main.c mapit.c mapaux.c mem.c printit.c -LSRC = $(CSRC) parse.c -SRC = $(CSRC) parse.y makedb.c arpatxt.c - -pathalias: & $(OBJ) - $(CC) $(OBJ) $(LDFLAGS) -o pathalias - -all: pathalias makedb arpatxt - -$(OBJ): $(HDRS) - -parse.c: parse.y $(HDRS) - $(YACC) $(YFLAGS) parse.y - echo '#define YYDEBUG' > parse.c - sed -e '/^# line/d' -e 's/yydebug = 0/yydebug = $(YYDEBUG)/' y.tab.c >> parse.c - -makedb: makedb.o - $(CC) makedb.o $(LDFLAGS) $(DBM) -o makedb - -makedb.o: config.h - -arpatxt: arpatxt.o - $(CC) arpatxt.o $(LDFLAGS) -o arpatxt - -clean: - rm -f *.o y.tab.? parse.c - -tags: $(SRC) $(HDRS) - ctags -w $(SRC) $(HDRS) - -bundle: README CHANGES pathalias.8 Makefile ${HDRS} ${SRC} arpa-privates make.honey - @bundle README CHANGES pathalias.8 Makefile ${HDRS} ${SRC} arpa-privates make.honey - -bundle1: README CHANGES pathalias.8 Makefile ${HDRS} - @bundle README CHANGES pathalias.8 Makefile ${HDRS} - -bundle2: addlink.c addnode.c local.c main.c - @bundle addlink.c addnode.c local.c main.c - -bundle3: mapit.c mapaux.c - @bundle mapit.c mapaux.c - -bundle4: mem.c printit.c parse.y - @bundle mem.c printit.c parse.y makedb.c - -bundle5: makedb.c arpatxt.c arpa-privates make.honey - @bundle makedb.c arpatxt.c arpa-privates make.honey - -ftp: - @make -s bundle | compress > /usr/ftp/pub/honey/pathalias.Z - -make.honey: makefile - @cp makefile make.honey - -lint: $(LSRC) - lint -hbu $(CFLAGS) $(LSRC) - lint makedb.c - - -# the remainder is site specific. - -LOCAL = paths/citi paths/internet -FILES = pp/* $(LOCAL) - -paths/internet: hosts.txt arpa-privates local.hosts arpatxt - arpatxt -vfi -g citi -g umix -g mailrus -p arpa-privates local.hosts hosts.txt > paths/internet - -AVOID = - -# map output (input, really) to lower case; verbose; terminal domains -ARGS = -iD - -PARGS=$(ARGS) $(AVOID) $(FILES) -# desperation debugging -- examine the costs. -costs: - pathalias -icvvD ${PARGS} 2>error.costs | awk '{printf("%s\t%s\t%s\n", $$2, $$1, $$3)}' | sort -o pa.costs - -# make one BIG file. a BIG bad idea. -cat: - for i in $(FILES); do echo "file {$$i}"; cat $$i; echo 'private {}'; done > CAT - -# make a pathparse database. -g is undocumented. -edges: - pathalias -g edges $(PARGS) 2>ERRORS > edges.hosts -# makedb edges pa - -# kill bogus domains with mr. grep, then sort -POSTPROC = egrep -v '(\.(com|edu|mil|gov|net|org|arpa|[a-z][a-z]) .*!.*!)|(.\.(com|edu|mil|gov|net|org|arpa|[a-z][a-z]) )' | sort - -# round up the usual suspects -citi dwon umix mailrus: $(LOCAL) - pathalias -l $@ $(PARGS) | $(POSTPROC) > $@ //GO.SYSIN DD make.honey exit