|
|
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 a
Length: 25793 (0x64c1)
Types: TextFile
Names: »atalkad.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦3b20aab50⟧ »EurOpenD3/network/snmp/kip-snmp.91.tar.Z«
└─⟦b503a39fe⟧
└─⟦this⟧ »kip/etc/atalkad.c«
#ifndef lint
static char sccsid[] = "@(#)atalkad.c 1.2 (Stanford) 9/87";
#endif
/*
* Appletalk administration daemon.
*
* Answers request packets from client appletalk gateways by supplying
* the appletalk-to-ip network configuration table and the local
* appletalk gateway configuration information.
*/
/*
* (C) 1986, Stanford Univ. CSLI.
* May be used but not sold without permission.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <netinet/in.h>
#define iaddr_t long
#include "gwctl.h"
#include "ab.h"
#include <signal.h>
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <ctype.h>
#include <netdb.h>
/* for 4.2 systems */
#ifndef FD_SETSIZE
# define FD_SETSIZE sizeof(int)*8
# define NFDBITS sizeof(int)*8
# define howmany(x,y) (1)
# define FD_SET(n, p) (p)->fds_bits[0] |= (1<<(n))
# define FD_CLR(n, p) (p)->fds_bits[0] &= ~(1<<(n))
# define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
# define FD_ZERO(p) bzero((char *)p, sizeof(*p))
#endif
#ifndef ATALKATAB
#define ATALKATAB "/etc/atalkatab"
#endif
#ifndef ATALKALOG
#define ATALKALOG "/usr/adm/atalkalog"
#endif
#ifndef ATALKAPID
#define ATALKAPID "/usr/adm/atalkapid"
#endif
int debug;
extern int errno;
struct sockaddr_in sin = { AF_INET };
int s; /* socket fd */
struct sockaddr_in fsin; /* foreign sockaddr_in */
int fsinlen;
int sig, sigint(), sighup();
struct aaconf aa; /* receive packet */
struct aaconf aas; /* send packet */
struct timeval tvwait; /* timer for select */
/* Mask of high 3 bytes of a network address */
iaddr_t node_mask;
/*
* Globals below are associated with the atalka database file (atalkatab).
*/
char *atalkatab = ATALKATAB;
char *atalkalog = ATALKALOG;
char *atalkapid = ATALKAPID;
FILE *fp;
char line[256]; /* line buffer for reading atalkatab */
char *linep; /* pointer to 'line' */
int linenum; /* current line number in atalkatab */
#define NANETS 64 /* max number of 'anets' structs */
struct anets {
u_short net; /* atalk net */
u_char flags; /* flags, see aroute* in gwctl.h */
u_char confsize; /* size of databytes in conf below */
iaddr_t iaddr; /* ip address */
char zone[32]; /* zone name */
char conf[64]; /* configuration info, if kbox */
} anets[NANETS];
/* Internal format of conf structure */
struct conf {
iaddr_t ipbroad; /* broadcast addr on ether */
iaddr_t ipname; /* address of name server */
iaddr_t ipdebug; /* address of debug host */
iaddr_t ipfile; /* address of file server */
u_long ipother[4]; /* other addresses passed via IPGP */
#define ipsmask anetet /* old use for this field */
u_short anetet; /* ethertalk net number of enet */
#define ipsshift startddpWKSUnix /* old: subnet shift (unused) */
u_short startddpWKSUnix; /* start of unix WKS udp ports */
u_long flags; /* various bit flags */
#define conf_stayinzone 0x1 /* no looking at other zones */
#define conf_laserfilter 0x2 /* NBP filtering for LaserWriters */
#define conf_tildefilter 0x4 /* NBP filtering, "name~" */
u_short ipstatic; /* number of static IP addrs */
u_short ipdynamic; /* number of dynamic IP addrs */
u_short atneta; /* atalk net #, appletalk */
u_short atnete; /* atalk net #, ethernet */
} conf_proto;
int nanets; /* current number of anets */
long modtime; /* last modification time of atalkatab */
long size; /* last known size of file */
char aroutes[512]; /* route tuples built by buildart() */
int arouteslen;
char azones[512]; /* zone table built by buildzone() */
int azoneslen;
int scanonly = 0;
usage()
{
printf("usage: atalkad [-c filename] [-debug] [route|boot|exit]\n");
printf("usage: -c means check file\n");
exit(1);
}
main(argc, argv)
char *argv[];
{
register int n;
FILE *filep;
int pid;
for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
if (argv[0][0] == '-') {
switch (argv[0][1]) {
case 'd':
debug++;
break;
case 'c':
if (argv[0][2]) {
atalkatab = argv[0]+2;
} else if (argc > 1 && argv[1]) {
atalkatab = argv[1];
argc--, argv++;
}
scanonly++;
break;
default:
usage();
}
continue;
}
if (scanonly)
usage();
if (strcmp(argv[0], "boot") == 0)
sig = SIGINT;
else if (strcmp(argv[0], "route") == 0)
sig = SIGHUP;
else if (strcmp(argv[0], "exit") == 0)
sig = SIGKILL;
else
usage();
if ((filep = fopen(atalkapid, "r")) == NULL
|| fscanf(filep, "%d", &pid) != 1
|| kill(pid, sig) < 0) {
printf("failed to send signal to daemon\n");
exit(1);
} else {
printf("sent signal to daemon\n");
exit(0);
}
}
if (scanonly) {
readtab();
dumptab();
exit(0);
}
if (debug == 0) {
int t, f;
if (fork())
exit(0);
for (f = 0; f < 10; f++)
(void) close(f);
(void) open("/", 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
t = open("/dev/tty", 2);
if (t >= 0) {
ioctl(t, TIOCNOTTY, (char *)0);
(void) close(t);
}
}
log("### ATALKA daemon starting");
pid = getpid();
if ((filep = fopen(atalkapid, "w")) == NULL) {
log("couldnt create pid file %s\n", atalkapid);
exit(1);
}
fprintf(filep, "%d", pid);
fclose(filep);
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
while ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
log("socket call failed");
sleep(5);
}
sin.sin_port = htons(aaPort);
if (bind(s, (caddr_t)&sin, sizeof (sin), 0) < 0) {
log("bind call failed");
exit(1);
}
/* fill in node mask in a machine independent manner */
node_mask = inet_addr("255.255.255.0");
readtab();
for (;;) {
fsinlen = sizeof (fsin);
n = recvfrom(s, (caddr_t)&aa, sizeof aa,
0, (caddr_t)&fsin, &fsinlen);
if (n < 0) {
if (errno != EINTR) {
log("recv failed");
exit(1);
}
readtab();
sendall(sig);
continue;
}
if (n < aaconfMinSize || ntohl(aa.magic) != aaMagic)
continue;
readtab();
sendreply();
}
}
/*
* Interrupts are used to signal type of sendall().
*/
sighup() { sig = aaROUTEI; }
sigint() { sig = aaRESTART; }
/*
* Send reply to packet aa.
*/
sendreply()
{
register struct anets *an;
register n;
switch (aa.type) {
case aaCONF:
for (an = &anets[0], n = 0 ; n < nanets ; an++, n++)
if (an->iaddr == aa.ipaddr && an->confsize &&
(an->flags & arouteKbox) &&
(an->flags & arouteEtalk) == 0)
goto found;
log("aaCONF from %s ***** not in table", inet_ntoa(aa.ipaddr));
return;
found:
log("aaCONF to %s", inet_ntoa(aa.ipaddr));
n = an->confsize;
bcopy(an->conf, aa.stuff, n);
break;
case aaZONE:
log("aaZONE to %s", inet_ntoa(aa.ipaddr));
n = azoneslen;
bcopy(azones, aa.stuff, n);
break;
case aaZONEQ:
log("aaZONEq from %s", inet_ntoa(aa.ipaddr));
if ((n = zipinput()) <= 0)
return; /* drop */
break;
case aaROUTEI:
log("aaROUTEI to %s", inet_ntoa(aa.ipaddr));
n = arouteslen;
bcopy(aroutes, aa.stuff, n);
break;
default:
/* don't reply here! */
return;
}
aa.count = htons(n);
sendto(s, (caddr_t)&aa, aaconfMinSize + n, 0,
&fsin, sizeof fsin);
}
char *
netstring(n)
u_short n;
{
int net;
static char mynetstr[30];
net = ntohs(n);
sprintf(mynetstr, "%d.%d", (net>>8) & 0xff, net & 0xff);
return(mynetstr);
}
/*
* return pointer to zone name
* NULL if none
*/
char *
zoneof(net)
u_short net;
{
register struct anets *an;
int n;
for (an = &anets[0], n=0 ; n < nanets ; an++, n++)
if (net == an->net)
return(an->zone);
return(NULL);
}
/*
* return a value that is always printable
*
*/
char *
pzoneof(net)
u_short net;
{
char *p = zoneof(net);
return(p == NULL ? "unknown" : p);
}
dumptab()
{
register struct anets *an;
register n, size;
char *hostnameof();
struct conf *conf;
iaddr_t rs, re;
size = 0;
for (an = &anets[0], n = 0 ; n < nanets ; an++, n++) {
printf("Route %s %s, ", netstring(an->net), an->zone);
if ((an->flags & arouteKbox) && (an->flags & arouteEtalk) == 0)
printf(" Kinetics box");
if (an->flags & arouteCore)
printf(" core gateway");
if (an->flags & arouteHost)
printf(" host is redirector");
if (an->flags & arouteNet)
if (an->flags & arouteBMask)
printf(" net %d", an->flags & arouteBMask);
else
printf(" net 0: host is client");
if ((an->flags & (arouteKbox|arouteEtalk)) == (arouteKbox|arouteEtalk))
printf(" EtherTalk");
printf(" at %s", hostnameof(an->iaddr));
putchar('\n');
if ((an->flags & arouteKbox) && (an->flags & arouteEtalk) == 0) {
conf = (struct conf *)an->conf;
printf("\tIP Broadcast: %s, ", inet_ntoa(conf->ipbroad));
if (conf->ipname == conf->ipdebug) {
printf("IP name and debug: %s\n", hostnameof(conf->ipname));
printf("\tIP file server (unused)", hostnameof(conf->ipfile));
} else {
printf("IP name: %s\n",hostnameof(conf->ipname));
printf("\tIP debug %s, ", hostnameof(conf->ipdebug));
printf("IP file server (unused)", hostnameof(conf->ipfile));
}
if (ntohl(conf->flags) & conf_stayinzone)
printf(", marked stay in zone");
if (ntohl(conf->flags) & conf_laserfilter)
printf(", laserwriters stay in zone");
if (ntohl(conf->flags) & conf_tildefilter)
printf(", tilde marked names stay in zone");
putchar('\n');
if (conf->startddpWKSUnix == htons(defddpWKSUnix))
printf("\tUDP Port range for WKS starts at %d (old range)\n",
defddpWKSUnix);
else
printf("\tUDP Port range for WKS starts at %d\n",
ntohs(conf->startddpWKSUnix));
#ifdef SHORTFORMAT
if (conf->ipstatic)
printf("\t%d ", ntohs(conf->ipstatic));
else
printf("\tNo");
printf(" static ip addresses, ");
if (conf->ipdynamic)
printf("\t%d ", ntohs(conf->ipdynamic));
else
printf("\tNo");
printf(" dynamic ip addresses\n");
#else
if (conf->ipstatic) {
re = rs = ntohl(an->iaddr)+1;
re += (ntohs(conf->ipstatic)-1);
printf("\tIP static address range: %s",
inet_ntoa(htonl(rs)));
printf(" %s\n",inet_ntoa(htonl(re)));
} else {
printf("\tIP static address range: empty\n");
re = ntohl(an->iaddr);
}
if (conf->ipdynamic) {
re = rs = re+1;
re += (ntohs(conf->ipdynamic)-1);
printf("\tIP dynamic address range: %s",
inet_ntoa(htonl(rs)));
printf(" %s\n",inet_ntoa(htonl(re)));
} else {
printf("\tIP dynamic address range: empty\n");
re = ntohl(an->iaddr);
}
#endif
printf("\tKbox interfaces:\n");
printf("\t\tlocaltalk: %s zone %s\n", netstring(conf->atneta),
pzoneof(conf->atneta));
printf("\t\tKIP: %s zone %s\n", netstring(conf->atnete),
pzoneof(conf->atnete));
if (conf->anetet) {
printf("\t\tEtherTalk: %s zone %s\n", netstring(conf->anetet),
pzoneof(conf->anetet));
}
}
}
}
/*
* Build arouteTuple's into area provided by caller.
* Return byte count of tuples deposited.
*/
buildart(at, maxsize)
register struct arouteTuple *at;
int maxsize;
{
register struct anets *an;
register n, size;
size = 0;
for (an = &anets[0], n = 0 ; n < nanets ; an++, n++, at++) {
size += sizeof *at;
at->node = an->iaddr;
at->net = an->net;
at->flags = an->flags;
at->hops = 0; /* start at one - incremented in gateway */
}
log("art build: %d entries, %d maximum",
size/(sizeof(struct arouteTuple)),
maxsize/(sizeof(struct arouteTuple)));
if (size > maxsize)
log("art build: routing table too big!!");
if (size > (maxsize - 10) )
log("art build: routing table size %d is near maximum of %d",
size, maxsize );
return (size);
}
#define MAXZ 32
/*
* Build zones structure to be returned by aaZONE.
*/
buildzones(az, azlen)
char *az;
int azlen;
{
char zname[MAXZ][33];
int nzname = 0;
char netzone[NANETS];
register i, iz, n;
register char *cp;
int zonenamelen = 0;
/* make a pass thru anets, finding all unique zone names. */
for (i = 0 ; i < nanets ; i++) {
for (iz = 0 ; iz < nzname ; iz++)
if (strcmp(anets[i].zone, zname[iz]) == 0)
goto found;
/* not found, make a new name */
strcpy(zname[iz], anets[i].zone);
zonenamelen += strlen(zname[iz]) + 1;
netzone[i] = iz;
nzname++;
continue;
/* found it, note the zname index */
found:
netzone[i] = iz;
}
/*
* Build structure to send to gateway. Looks like:
* net# net# ... 0 zonename
* net# net# ... 0 zonename
* 0xFFFF.
*/
cp = az;
for (iz = 0 ; iz < nzname ; iz++) {
for (i = 0 ; i < nanets ; i++) {
if (netzone[i] != iz)
continue;
/* anets[].net has been swapped by readtab */
*cp++ = (ntohs(anets[i].net) >> 8);
*cp++ = ntohs(anets[i].net);
}
*cp++ = 0; *cp++ = 0;
*cp++ = n = strlen(zname[iz]);
bcopy(zname[iz], cp, n);
cp += n;
}
*cp++ = 0xFF; *cp++ = 0xFF;
n = cp - az; /* length of table */
if (n > sizeof(azones)) {
log("buildzones: ZIP table too large");
log("buildzones: don't worry if you are using a KIP later than 1/88");
} else if (n > (sizeof(azones)-10))
log("buildzones: ZIP table size %d approaching maximum of %d",
n, sizeof(azones));
log("zone names take %d bytes in gateway");
return (n);
}
/*
* Send aaRESTART or aaROUTEI to all gateways.
*/
sendall(sig)
{
register struct anets *an;
register n;
int trys, count, rcount;
fd_set fds;
struct sockaddr_in tsin;
tsin = sin;
log("sendall(%s)", sig == aaRESTART ? "aaRESTART" : "aaROUTEI");
aas.magic = htonl(aaMagic); /* setup send packet */
aas.type = sig;
aas.flags = 0;
if (sig == aaROUTEI) {
bcopy(aroutes, aas.stuff, arouteslen);
count = arouteslen;
} else {
count = 0;
}
aas.count = htons(count);
count += aaconfMinSize;
/*
* send to each kbox in the table.
*/
for (an = &anets[0], n = 0 ; n < nanets ; an++, n++) {
if ((an->flags & arouteKbox) == 0 || (an->flags & arouteEtalk))
continue;
trys = 0;
tsin.sin_addr.s_addr = an->iaddr;
sendto(s, (caddr_t)&aas, count, 0, &tsin, sizeof tsin);
/*
* receive until we get a good reply or timeout.
*/
for (;;) {
FD_ZERO(&fds);
FD_SET(s, &fds);
tvwait.tv_sec = 2; /* select waits 2 seconds */
tvwait.tv_usec = 0;
if (select(NFDBITS, &fds, 0, 0, &tvwait) != 1) {
/* timeout */
if (++trys < 4) {
sendto(s, (caddr_t)&aas,
count, 0, &tsin, sizeof tsin);
continue;
}
log("no response from %s",
inet_ntoa(an->iaddr));
break;
}
fsinlen = sizeof fsin;
rcount = recvfrom(s, (caddr_t)&aa, sizeof aa,
0, (caddr_t)&fsin, &fsinlen);
if (rcount < 0) {
if (errno == EINTR)
continue;
log("recv failed");
exit(1);
}
if (rcount < aaconfMinSize
|| ntohl(aa.magic) != aaMagic)
continue;
if (aa.ipaddr != an->iaddr) {
sendreply();
continue;
}
/* our request got thru! */
sendreply();
break;
}
}
log("sendall(%s) complete",sig==aaRESTART ? "aaRESTART" : "aaROUTEI");
}
/*
* check over configurations
*
*/
checkconfigs()
{
int i;
struct anets *an;
struct conf *cp;
int rangestart = 0;
int rangeconflict = 0;
int badrange = 0;
for (an = anets, i = 0; i < nanets; i++, an++) {
if (an->confsize >= sizeof(struct conf)) {
cp = (struct conf *)an->conf;
if (!cp->startddpWKSUnix) {
cp->startddpWKSUnix = htons(defddpWKSUnix);
if (rangestart) {
if (rangestart != cp->startddpWKSUnix)
rangeconflict = 1;
} else rangestart = cp->startddpWKSUnix;
} else {
if (rangestart) {
if (rangestart != cp->startddpWKSUnix)
rangeconflict = 1;
} else rangestart = cp->startddpWKSUnix;
}
}
}
rangestart = ntohs(rangestart);
if (rangeconflict)
log("Conflict in UDP WKS range start!");
else if (rangestart != 200 && rangestart != defddpWKSUnix) {
log("WARNING - UDP WKS range start %d is non-standard",
ntohs(rangestart));
}
}
/*
* Read atalkatab database file. Avoid rereading the file if the
* write date hasnt changed since the last time we read it.
*/
readtab()
{
struct stat sbuf1, sbuf;
register char *sp, *cpp;
int v;
register i;
char st[128], *cp;
register struct anets *an;
iaddr_t iaddr;
if (fp == 0) {
if ((fp = fopen(atalkatab, "r")) == NULL) {
log("can't open %s", atalkatab);
exit(1);
}
}
if (fstat(fileno(fp), &sbuf1) < 0)
goto reopen;
if (stat(atalkatab, &sbuf) < 0)
goto reopen;
if (sbuf1.st_dev == sbuf.st_dev && /* different... */
sbuf1.st_ino == sbuf.st_ino && /* ...file */
sbuf1.st_size == size && /* nec? */
sbuf.st_size == size &&
sbuf1.st_mtime == modtime && /* nec? */
sbuf.st_mtime == modtime)
return;
reopen:
if (fp)
fclose(fp);
if ((fp = fopen(atalkatab, "r")) == NULL) {
log("can't open %s", atalkatab);
exit(1);
}
fstat(fileno(fp), &sbuf);
log("(re)reading %s", atalkatab);
modtime = sbuf.st_mtime;
size = sbuf.st_size;
nanets = 0;
an = &anets[-1];
linenum = 0;
/*
* read and parse each line in the file.
*/
for (;;) {
if (fgets(line, sizeof line, fp) == NULL)
break; /* done */
if ((i = strlen(line)))
line[i-1] = 0; /* remove trailing newline */
linep = line;
linenum++;
if (line[0] == '#' || line[0] == 0)
continue; /* skip comment lines */
if (line[0] == ' ' || line[0] == '\t')
goto confinfo;
/*
* lines not beginning with white space
* represent a new net #
*/
if (++nanets > NANETS) {
log("'anets' table length exceeded");
exit(1);
}
an++;
cp = an->conf; /* store following lines here */
an->confsize = 0;
getfield(st, sizeof st);
an->net = htons(getashort(st));
getfield(st, sizeof st);
i = 0;
/* parse flags */
for (cpp = st ; *cpp ; cpp++) {
if (isupper(*cpp))
*cpp = tolower(*cpp);
switch (*cpp) {
case 'c':
i |= arouteCore; break;
case 'k':
i |= arouteKbox; break;
case 'h':
i |= arouteHost; break;
case 'n':
i |= arouteNet; break;
case 'e':
i |= (arouteEtalk|arouteKbox); break;
case '0': case '1': case '2': case '3':
i |= (*cpp - '0'); break;
default:
log("bad switch %s, linenum %d", st, linenum);
}
}
an->flags = i;
getfield(st, sizeof st);
an->iaddr = getiaddr(st);
getfield(an->zone, sizeof(an->zone));
continue;
confinfo:
/*
* lines beginning with white space
* are configuration data for gateway.
*/
for (;;) { /* for each field in line */
int len;
getfield(st, sizeof st);
sp = st;
if (*sp == 0)
break;
if (isupper(*sp))
*sp = tolower(*sp);
switch (*sp++) {
case '%':
/* escape code, one of 'n' */
if (isupper(*sp))
*sp = tolower(*sp);
switch (*sp++) {
int flag;
case 'n':
/* decide which type of network based on */
/* the offset in the config structure */
if (cp - an->conf ==
(char *)&conf_proto.atnete-(char *)&conf_proto)
flag = arouteNet;
else if (cp - an->conf ==
(char*)&conf_proto.anetet-(char*)&conf_proto)
flag = arouteKbox|arouteEtalk;
else if (cp - an->conf ==
(char*)&conf_proto.atneta-(char*)&conf_proto)
flag = arouteKbox;
else {
log("%%N at unexpected offset %d, line %d\n",
cp - an->conf, linenum);
flag = arouteKbox;
}
if ((*(short *)cp =
getanet(flag, an->iaddr)) == 0)
log("%%N not set, line %d\n", linenum);
cp += 2;
an->confsize += 2;
break;
default:
log("bad field type %s, linenum %d", st, linenum);
break;
}
break;
case 'i':
/* IP address name or number */
iaddr = getiaddr(sp);
bcopy((caddr_t)&iaddr, cp, sizeof iaddr);
cp += sizeof iaddr;
an->confsize += sizeof iaddr;
break;
case 'l':
if ((int)cp & 1)
goto badalign;
*(long *)cp = htonl(atoii(sp));
cp += 4;
an->confsize += 4;
break;
case 's':
if ((int)cp & 1)
goto badalign;
*(short *)cp = htons(getashort(sp));
cp += 2;
an->confsize += 2;
break;
case 'c':
*cp = atoii(sp);
cp++;
an->confsize++;
break;
case '"':
len = strlen(sp) - 1; /* drop trailing " */
bcopy(sp, cp, len);
cp += len;
*cp++ = 0;
len++;
an->confsize += len;
break;
case '\'': /* pascal string */
len = strlen(sp) - 1; /* drop trailing ' */
*cp++ = len;
bcopy(sp, cp, len);
cp += len;
len++; /* skip over length field */
*cp++ = 0;
len++;
an->confsize += len;
break;
default:
log("bad field type %s, linenum %d",
st, linenum);
break;
}
continue; /* get next field in line */
badalign:
log("long/short bad alignment %s, linenum %d",
st, linenum);
break;
}
/* get next line */
}
/* end of file */
checkconfigs();
arouteslen = buildart((struct arouteTuple *)aroutes, sizeof aroutes);
azoneslen = buildzones(azones, sizeof azones);
}
/*
* Get next field from 'line' buffer into 'str'. 'linep' is the
* pointer to current position. No imbeded spaces are allowed in the
* fields; however, an underscore '_' will convert to a space. (To get
* a real underscore, double it.)
*/
getfield(str, len)
char *str;
{
register char *cp = str;
register und;
for ( ; *linep && (*linep == ' ' || *linep == '\t') ; linep++)
; /* skip spaces/tabs */
if (*linep == 0 || *linep == '#') {
*cp = 0;
return;
}
und = 0;
len--; /* save a spot for a null */
for ( ; *linep && *linep != ' '
&& *linep != '\t' && *linep != '#' ; linep++) {
if (*linep == '_') {
if (und) {
und = 0; cp--; len++;
} else {
und++; *linep = ' ';
}
} else {
und = 0;
}
*cp++ = *linep;
if (--len <= 0) {
*cp = 0;
log("string truncated: %s, linenum %d", str, linenum);
return;
}
}
*cp = 0;
}
/*
* Ascii to integer, with base check.
*/
atoii(s)
register char *s;
{
int v;
char *c;
if (isupper(*s))
*s = tolower(*s);
if (*s == 'x' || *s == 'h') {
c = "%x";
s++;
} else {
c = "%d";
}
if (sscanf(s, c, &v) != 1)
log("bad numeric field %s, linenum %d", s, linenum);
return (v);
}
/*
* Get an internet address as a hostname or dot format string.
*/
getiaddr(st)
register char *st;
{
iaddr_t iaddr;
register struct hostent *host;
if (isdigit(*st)) {
if ((iaddr = inet_addr(st)) == -1 || iaddr == 0)
log("bad ipaddress %s, linenum %d", st, linenum);
} else {
if ((host = gethostbyname(st)) == 0)
log("bad hostname %s, linenum %d", st, linenum);
bcopy(host->h_addr, (caddr_t)&iaddr, sizeof iaddr);
}
return (iaddr);
}
/*
* Get a short number or address.
*/
getashort(st)
register char *st;
{
register char *cp;
if ((cp = index(st, '.')) == 0)
return (atoii(st));
*cp++ = 0;
return ((atoii(st)<<8) | atoii(cp));
}
/*
* log an error message
*/
log(fmt, args)
char *fmt;
{
FILE *fp;
long time(), tloc;
struct tm *tm, *localtime();
if (debug)
fp = stderr;
else if (scanonly)
fp = stdout;
else if ((fp = fopen(atalkalog, "a+")) == NULL)
return;
time(&tloc);
tm = localtime(&tloc);
fprintf(fp, "%d/%d %02d:%02d ", tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min);
_doprnt(fmt, &args, fp);
putc('\n', fp);
if (fp != stderr && fp != stdout)
fclose(fp);
}
\f
/*
* getanet - scan through the table so far and find an appletalk network
* number. Called from the %x fields of the config structure
*
* flag field:
* arouteNet - match an IP address, scan for a net route that matches addr
* arouteKbox - scan for a route using this host
* arouteKbox|arouteETalk - scan for an Ethertalk net using this host.
*
* Limitations: Only one bridge can be configured with a given Ethertalk
* network number this way. Network numbers referenced must be defined before
* use.
*/
getanet(flags, ia)
iaddr_t ia;
{
register int i;
struct anets *a;
/* Scan table in reverse order - slightly more efficent */
for(i = nanets-1; i >= 0; --i) {
a = &anets[i];
if ((flags == arouteNet &&
((a->flags & arouteNet) != 0 || (a->flags & arouteHost) != 0) &&
match_net(a->flags, ia, a->iaddr)) ||
(flags == arouteKbox &&
(a->flags & arouteKbox|arouteEtalk) == arouteKbox &&
a->iaddr == ia) ||
(flags == arouteKbox|arouteEtalk &&
(a->flags & flags) == flags &&
a->iaddr == ia))
return(a->net);
}
log("unable to match appletalk net (%x), line %d\n", flags, linenum);
return(0);
}
/*
* match_net - match a network number, using mask field stored in
* flags.
*/
match_net(flags, a1, a2)
iaddr_t a1, a2;
{
return((a1 & node_mask) == (a2 & node_mask));
}
char *
hostnameof(ipaddr)
struct in_addr ipaddr;
{
struct hostent *host;
host = gethostbyaddr(&ipaddr.s_addr, sizeof(ipaddr.s_addr), AF_INET);
if (!host)
return((char *)inet_ntoa(ipaddr));
return(host->h_name);
}
zipinput()
{
u_short buf[1000];
u_short *bp;
int icount;
int len;
u_char *p;
char *zn;
int zl;
struct ZIP zipin;
struct ZIP *z;
icount = ntohs(aa.count); /* remember incoming count */
bcopy(aa.stuff, &zipin, sizeof(struct ZIP));
if (zipin.command != zipQuery || zipin.count == 0)
return(-1);
/* get the list of networks */
bcopy(aa.stuff+sizeof(struct ZIP), buf, zipin.count * sizeof(u_short));
bp = buf;
z = (struct ZIP *)aa.stuff;
z->command = zipReply;
z->count = 0;
len = sizeof(struct ZIP);
for (p = (u_char *)(z+1); len<512&&zipin.count; zipin.count--, bp++) {
if ((zn = zoneof(*bp)) == NULL)
continue;
bcopy(bp, p, sizeof(u_short)); /* copy in network */
p+= sizeof(u_short); /* move along */
len+= sizeof(u_short); /* move along */
zl = *p = strlen(zn); /* get zone length */
p++; /* bounce */
len++;
z->count++;
bcopy(zn, p, zl); /* copy in zone name */
p += zl; /* bounce p ...*/
len += zl; /* ... and len */
}
return(len);
}