home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Copyright (c) 1991 Bolt Beranek and Newman, Inc.
- ** All rights reserved.
- **
- ** Redistribution and use in source and binary forms are permitted
- ** provided that: (1) source distributions retain this entire copyright
- ** notice and comment, and (2) distributions including binaries display
- ** the following acknowledgement: ``This product includes software
- ** developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
- ** documentation or other materials provided with the distribution and in
- ** all advertising materials mentioning features or use of this software.
- ** Neither the name of Bolt Beranek and Newman nor CREN/CSNET may be used
- ** to endorse or promote products derived from this software without
- ** specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- ** WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <setjmp.h>
- #include <sgtty.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/ioctl.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <net/if.h>
- #include <net/if_du.h>
- #include "diald.h"
- #include "dialupip.h"
-
- #ifdef sun
- #define GETDATAVAL(ifr) (*(int *)ifr.ifr_data)
- #define SETDATAVAL(ifr, i) (*(int *)(ifr).ifr_data = (i))
- #else
- #define GETDATAVAL(ifr) ((int)ifr.ifr_data)
- #define SETDATAVAL(ifr, i) ((ifr).ifr_data = (caddr_t)(i))
- #endif /* sun */
-
- /*
- ** Local Variables
- */
- static char device[12]; /* Device name */
- static char tty[12]; /* Modem in use */
- static int mypid;
- static int dialfout; /* Modem descriptor */
- static long startipkts; /* Starting input packet count */
- static long startopkts; /* Starting output packet count */
- static struct ifreq ifr;
- static int oldinactive; /* Old inactivity value */
- static struct sgttyb oldsgtty; /* Old TTY modes */
- static jmp_buf opentimeout; /* Used for open timeouts */
- static int sock; /* The global socket for use everywhere */
- static time_t starttime; /* Time call started */
- static time_t stoptime; /* Time call stopped */
- static long duration; /* Duration of call in seconds */
- static char sitename[30]; /* Name of site called */
-
-
- extern char *strerror();
-
-
-
- /*
- ** Log that a call failed.
- */
- void
- failcall(devname, mesg)
- char *devname;
- char *mesg;
- {
- static char WHERE[] = "failcall";
- int s;
- struct ifreq ifr;
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't create socket for \"%s\", %m",
- devname);
- d_log(DLOG_GENERAL, WHERE, "%s", mesg);
- return;
- }
-
- (void)strcpy(ifr.ifr_name, devname);
- if (ioctl(s, SIOCFAILCALL, (caddr_t)&ifr) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCFAILCALL on \"%s\", %m",
- devname);
- d_log(DLOG_GENERAL, WHERE, "%s", mesg);
- return;
- }
-
- d_log(DLOG_ALL, WHERE, "Did SIOCFAILCALL on \"%s\"", devname);
- d_log(DLOG_ALL, WHERE, "%s", mesg);
- }
-
-
- /*
- ** Get the packet counts from the interface.
- */
- static void
- getpacketcounts(ipkts, opkts)
- long *ipkts;
- long *opkts;
- {
- static char WHERE[] = "getpacketcounts";
-
- /* Zero out the counts */
- *ipkts = *opkts = 0;
-
- if (ioctl(sock, SIOCGIPKTS, (caddr_t)&ifr) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCGIPKTS for \"%s\", %m", device);
- unlock_pid();
- exit(1);
- }
- *ipkts = (long)GETDATAVAL(ifr);
-
- if (ioctl(sock, SIOCGOPKTS, (caddr_t)&ifr) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCGOPKTS for \"%s\", %m", device);
- unlock_pid();
- exit(1);
- }
- *opkts = (long)GETDATAVAL(ifr);
- }
-
-
- static int
- set_inactivity(max_inactivity)
- int max_inactivity;
- {
- static char WHERE[] = "set_inactivity";
- int old;
-
- /* Get the old value */
- if (ioctl(sock, SIOCGATIMEO, (caddr_t)&ifr) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCGATIMEO for \"%s\", %m", device);
- old = -1;
- }
- else
- old = GETDATAVAL(ifr);
-
- /* If the new time is negative, then just return the current value */
- if (max_inactivity < 0) {
- d_log(DLOG_DIAG, WHERE, "Timeout for \"%s\" unchanged from %d",
- device, old);
- return old;
- }
-
- /* Set the inactivity timer */
- SETDATAVAL(ifr, max_inactivity);
- if (ioctl(sock, SIOCSATIMEO, (caddr_t)&ifr) < 0)
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCSATIMEO for \"%s\", %m", device);
- else if (max_inactivity)
- d_log(DLOG_INFO, WHERE, "Timeout for \"%s\" set to %d",
- device, max_inactivity);
- else
- d_log(DLOG_INFO, WHERE,
- "Timeout for \"%s\" disabled; must be brought down manually",
- device);
-
- return old;
- }
-
-
- static void
- writelog()
- {
- static char WHERE[] = "writelog";
- FILE *F;
- long hours;
- long minutes;
- long seconds;
-
- /* Just in case... */
- if (starttime == 0)
- return;
-
- if ((F = fopen(CALL_LOG, "a")) == NULL) {
- d_log(DLOG_DIAG, WHERE, "Can't open call log, %m");
- return;
- }
-
- hours = duration / 3600;
- minutes = (duration - hours * 3600) / 60;
- seconds = duration - hours * 3600 - minutes * 60;
-
- (void)fprintf(F, "%-16.16s %-19.19s %02ld:%02ld:%02ld %s\n",
- sitename, ctime(&stoptime), hours, minutes, seconds, progname);
- (void)fclose(F);
- }
-
-
- /*
- ** Catch signal and exit.
- */
- static void
- hangup(sig)
- int sig;
- {
- static char WHERE[] = "hangup";
- long totalpkts;
- long endipkts;
- long endopkts;
- int disc;
- int status;
-
- /* Now ignore the signals since we're shutting down. */
- (void)signal(SIGHUP, SIG_IGN);
- (void)signal(SIGTERM, SIG_IGN);
- d_log(DLOG_ALL, WHERE, "Process %d got signal %d for \"%s\"",
- mypid, sig, device);
-
- /* Let go of the lock file */
- (void)uu_unlock(tty);
- unlock_pid();
-
- /* Log the statistics */
- (void)time(&stoptime);
- duration = stoptime - starttime;
- writelog();
-
- getpacketcounts(&endipkts, &endopkts);
- totalpkts = (endipkts - startipkts) + (endopkts - startopkts);
- d_log(DLOG_INFO, WHERE, "Outbound interface \"%s\" up %ld seconds",
- device, duration);
- d_log(DLOG_DIAG, WHERE,
- "Inpackets = %ld, Outpackets = %ld, Average = %.2f packets/sec",
- endipkts - startipkts, endopkts - startopkts,
- totalpkts ? ((float)totalpkts) / ((float)duration) : 0);
-
- /* Restore the inactivity counter, disconnect and exit */
- (void)set_inactivity(oldinactive);
-
- status = 0;
-
- /* Bring back the line discipline. */
- disc = NTTYDISC;
- if (ioctl(dialfout, TIOCSETD, (caddr_t)&disc) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETD \"%s\", %m", device);
- status = 1;
- }
-
- /* Reset the TTY modes. */
- if (ioctl(dialfout, TIOCSETP, (caddr_t)&oldsgtty) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETP \"%s\", %m", device);
- status = 1;
- }
-
- /* Drop DTR. */
- if (ioctl(dialfout, TIOCCDTR, (caddr_t)0) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't TIOCCDTR \"%s\", %m", device);
- status = 1;
- }
-
- /* All done, report that we made it. */
- d_log(DLOG_GENERAL, WHERE, "Disconnected \"%s\"", device);
- exit(status);
- }
-
-
- /*
- ** Set line to have the right discipline and modes.
- */
- static int
- duconnect(device)
- char *device;
- {
- static char WHERE[] = "duconnect";
- int dudisc;
- struct ifreq ifr;
- struct sgttyb sgtty;
- char *p;
- int uid;
-
- /* Get the current modes. */
- if (ioctl(dialfout, TIOCGETP, (caddr_t)&sgtty) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't TIOCGETP on \"%s\", %m", device);
- return CALL_IOCTL_ERR;
- }
- oldsgtty = sgtty;
-
- /* Set the new modes. */
- sgtty.sg_flags = RAW | ANYP;
- if (ioctl(dialfout, TIOCSETP, (caddr_t)&sgtty) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't TIOCSETP on \"%s\", %m", device);
- return CALL_IOCTL_ERR;
- }
-
- /* Find the device number and convert */
- /* NEED TO BE MORE INTELLIGENT ABOUT THIS */
- (void)strcpy(ifr.ifr_name, device);
- for (p = device; *p && !isdigit(*p); p++)
- ;
-
- #ifdef ifr_metric
- if (*p == '\0') {
- d_log(DLOG_GENERAL, WHERE, "Can't find unit number in \"%s\"", device);
- return CALL_BAD_IF;
- }
- ifr.ifr_metric = atoi(p);
- #endif
-
- /* Become root. */
- uid = getuid();
- if (setuid(0) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't setuid to root, %m");
- return CALL_NOSETUID;
- }
-
- /* Change to the DIP discipline. */
- dudisc = DUDISC;
- if (ioctl(dialfout, TIOCSETD, (caddr_t)&dudisc) < 0) {
- d_log(DLOG_GENERAL, WHERE,
- "Can't TIOCSETD on \"%s\", %m -- is DIP configured?",
- device);
- return CALL_IOCTL_ERR;
- }
-
- if (ioctl(dialfout, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
- d_log(DLOG_GENERAL, WHERE,
- "Can't SIOCSIFADDR on \"%s\", %m -- is device installed?",
- device);
- return CALL_IOCTL_ERR;
- }
-
- d_log(DLOG_ALL, WHERE, "Did SIOCISFADDR on \"%s\"",device);
- (void)setuid(uid);
- return CALL_SUCCESS;
- }
-
-
- /*
- ** Get a modem from the list of usable ones for this system and return
- ** the first one that isn't already in use. NOTE: We must respect locks
- ** made by uucp, tip, cmdf et al
- */
- static int
- find_modem(rp)
- REMOTE *rp;
- {
- register int i;
-
- for (i = 0; i < MAXDEVICES && rp->Lines[i][0]; i++)
- if (uu_lock(rp->Lines[i]) >= 0)
- return i;
- return -1;
- }
-
-
- /*
- ** Catch an alarm while waiting for the open to succeed.
- */
- static void
- open_timeout()
- {
- longjmp(opentimeout, 1);
- /* NOTREACHED */
- }
-
-
- static int
- makecall_real(rp)
- REMOTE *rp;
- {
- static char WHERE[] = "makecall";
- char devtty[30];
- FILE *fp;
- char logbuf[256];
- struct sgttyb sgtty;
- int stat;
- char *tname;
- int i;
-
- /* Open our own path to the terminal and close the old connections */
- if ((i = open("/dev/tty", O_RDONLY)) >= 0) {
- (void)ioctl(i, TIOCNOTTY, (caddr_t)0);
- (void)close(i);
- }
- (void)fclose(stdin);
- (void)fclose(stdout);
-
- /* Find a modem. */
- if ((i = find_modem(rp)) < 0) {
- (void)sprintf(logbuf,
- "Can't find modem for \"%s\" -- check lock files.",
- rp->Sitename);
- failcall(rp->Device, logbuf);
- return CALL_PERMISSION;
- }
- (void)strcpy(tty, rp->Lines[i]);
- (void)strcpy(sitename, rp->Sitename);
- (void)strcpy(device, rp->Device);
-
- /* Set up exit handler. */
- (void)signal(SIGHUP, hangup);
- (void)signal(SIGTERM, hangup);
-
- /* Set up a time-out handler. Main reason for the open timing-out is
- * because modem is off, or not configured correctly. */
- (void)sprintf(devtty, "/dev/%s", tty);
- (void)signal(SIGALRM, open_timeout);
- if (setjmp(opentimeout)) {
- /* Open failed. */
- (void)sprintf(logbuf, "Time-out opening modem \"%s\" for \"%s\"",
- devtty, rp->Sitename);
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_TTYTIMEOUT;
- }
-
- /* Open the modem port */
- (void)alarm(OPEN_TIMEOUT);
- if ((dialfout = open(devtty, O_RDWR)) < 0) {
- (void)sprintf(logbuf, "Can't open modem \"%s\" for \"%s\", %s",
- devtty, rp->Sitename, strerror(errno));
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_PERMISSION;
- }
-
- /* Turn off the timeout, record what we're using. */
- (void)alarm(0);
- (void)signal(SIGALRM, SIG_DFL);
- (void)record_pid(rp->Device);
-
- /* Get the TTY modes. */
- if (ioctl(dialfout, TIOCGETP, (caddr_t)&sgtty) < 0) {
- (void)sprintf(logbuf, "Can't TIOCGETP for \"%s\", %s",
- rp->Sitename, strerror(errno));
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_IOCTL_ERR;
- }
-
- /* Set the new bits. */
- if (rp->Speeds[i] > 0)
- sgtty.sg_ispeed = sgtty.sg_ospeed = rp->Speeds[i];
- sgtty.sg_flags |= CBREAK;
- sgtty.sg_flags &= ~ECHO;
-
- /* Set the new mode. */
- if (ioctl(dialfout, TIOCSETP, (caddr_t)&sgtty) < 0) {
- (void)sprintf(logbuf, "Can't TIOCSETP for \"%s\", %s",
- rp->Sitename, strerror(errno));
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_IOCTL_ERR;
- }
-
- /* Change process group, set hangup on close. */
- if (ioctl(dialfout, TIOCHPCL, (caddr_t)&sgtty) < 0) {
- (void)sprintf(logbuf, "Can't TIOCHPCL for \"%s\", %s",
- rp->Sitename, strerror(errno));
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_IOCTL_ERR;
- }
-
- /* Open up the modem port. */
- if ((fp = fdopen(dialfout, "r+")) == NULL) {
- (void)sprintf(logbuf, "Can't fdopen modem port for \"%s\"",
- rp->Sitename);
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_PERMISSION;
- }
-
- /* Set up the name of the transaction file. */
- tname = rp->Transcript[0] ? rp->Transcript : NULL;
-
- /* Now run the script. */
- d_log(DLOG_GENERAL, WHERE, "Attempting connection to \"%s\" via \"%s\"",
- rp->Sitename, rp->Device);
- if (runscript(rp, fp, tname) < 0) {
- (void)sprintf(logbuf, "Script \"%s\" for \"%s\" failed",
- rp->Script, rp->Sitename);
- failcall(rp->Device, logbuf);
- (void)uu_unlock(tty);
- return CALL_FAIL;
- }
-
- /* Connection set up, set the line discipline. */
- if ((stat = duconnect(rp->Device)) != CALL_SUCCESS) {
- (void)uu_unlock(tty);
- return stat;
- }
-
- /* Connection made - get things going */
- d_log(DLOG_GENERAL, WHERE, "Connected to \"%s\" via \"%s\"",
- sitename, device);
- return CALL_SUCCESS;
- }
-
- int
- makecall(rp)
- REMOTE *rp;
- {
- static char WHERE[] = "makecall";
- int uptime;
- int old_if;
- int old_soft;
-
- /* Record the PID */
- mypid = getpid();
-
- if (makecall_real(rp) != CALL_SUCCESS)
- return;
-
- /* Create a socket for gathering info. */
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- d_log(DLOG_GENERAL, WHERE, "Can't create socket for \"%s\", %m",
- device);
- unlock_pid();
- exit(1);
- }
-
- /* Set up info, collect starting stats. */
- (void)strcpy(ifr.ifr_name, device);
- oldinactive = set_inactivity(rp->Inactivity);
- (void)time(&starttime);
- getpacketcounts(&startipkts, &startopkts);
- d_log(DLOG_DIAG, WHERE,
- "Outbound interface \"%s\" starting ipkts = %ld, opkts = %ld",
- device, startipkts, startopkts);
-
- /* Now keep tabs on the interface */
- for (old_if = old_soft = 0, uptime = 0; ; ) {
- /* See if the IF flags changed. */
- if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCGIFFLAGS, %m");
- else if (ifr.ifr_flags != old_if) {
- d_log(DLOG_ALL, WHERE,
- "\"%s\" IF flags changed from 0x%04x to 0x%04x",
- device, old_if, ifr.ifr_flags);
- old_if = ifr.ifr_flags;
- }
-
- /* See if the soft flags changed. */
- if (ioctl(sock, SIOCGSOFTFLAGS, (caddr_t)&ifr) < 0)
- d_log(DLOG_GENERAL, WHERE, "Can't SIOCGSOFTFLAGS, %m");
- else if (GETDATAVAL(ifr) != old_soft) {
- d_log(DLOG_ALL, WHERE,
- "\"%s\" SOFT flags changed from 0x%04x to 0x%04x",
- device, old_soft, GETDATAVAL(ifr));
- old_soft = GETDATAVAL(ifr);
- }
-
- (void)sleep(UPTIME_INTERVAL * 60);
- uptime += UPTIME_INTERVAL;
- d_log(DLOG_INFO, WHERE, "Outbound interface \"%s\" up %d minutes",
- device, uptime);
- }
- }
-