/* * util.c * * Written by Archie Cobbs * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved. * See ``COPYRIGHT.whistle'' */ #include "ppp.h" #include "util.h" #include #include #include /* * DEFINITIONS */ #define MAX_FILENAME 1000 #define MAX_LINE_ARGS 50 #define BIG_LINE_SIZE 1000 #define MAX_OPEN_DELAY 2 #define MAX_LOCK_ATTEMPTS 30 /* * INTERNAL VARIABLES */ static const u_int16_t Crc16Table[]; static FILE *lockFp = NULL; /* * INTERNAL FUNCTIONS */ static int UuLock(const char *devname); static int UuUnlock(const char *devname); static void Escape(char *line); static char *ReadLine(FILE *fp, int *lineNum, char *result, int resultsize); static char HexVal(char c); static void IndexConfFile(FILE *fp, struct configfile **cf); struct configfiles *ConfigFilesIndex=NULL; #undef isspace #define isspace(c) (((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\r')?1:0) /* * LengthenArray() */ void LengthenArray(void *array, int esize, int *alenp, const char *type) { void **const arrayp = (void **)array; void *newa; newa = Malloc(type, (*alenp + 1) * esize); if (*arrayp != NULL) { memcpy(newa, *arrayp, *alenp * esize); Freee(type, *arrayp); } *arrayp = newa; (*alenp)++; } /* * ExecCmd() */ int ExecCmd(int log, const char *fmt, ...) { int rtn; char cmd[BIG_LINE_SIZE]; va_list ap; va_start(ap, fmt); vsnprintf(cmd, sizeof(cmd), fmt, ap); /* Log command on the console */ Log(log, ("[%s] exec: %s", bund->name, cmd)); /* Hide any stdout output of command */ snprintf(cmd + strlen(cmd), sizeof(cmd) - strlen(cmd), " >/dev/null 2>&1"); /* Do command */ if ((rtn = system(cmd))) Log(log, ("[%s] exec: command returned %d", bund->name, rtn)); /* Return command's return value */ va_end(ap); return(rtn); } /* * ParseLine() * * Parse arguments, respecting double quotes and backslash escapes. * Returns number of arguments, at most "max_args". This destroys * the original line. The arguments returned are Malloc()'d strings * which must be freed by the caller using FreeArgs(). */ int ParseLine(char *line, char *av[], int max_args, int copy) { int ac; char *s, *arg; /* Get args one at a time */ for (ac = 0; ac < max_args; ac++) { /* Skip white space */ while (*line && isspace(*line)) line++; /* Done? */ if (*line == 0) break; /* Get normal or quoted arg */ if (*line == '"') { /* Stop only upon matching quote or NUL */ for (arg = ++line; *line; line++) if (*line == '"') { *line++ = 0; break; } else if (*line == '\\' && line[1] != 0) { strcpy(line, line + 1); Escape(line); } } else { /* NUL terminate this argument at first white space */ for (arg = line; *line && !isspace(*line); line++); if (*line) *line++ = 0; /* Convert characters */ for (s = arg; *s; s++) if (*s == '\\') { strcpy(s, s + 1); Escape(s); } } /* Make a copy of this arg */ if (copy) { strcpy(av[ac] = Malloc(MB_CMD, strlen(arg) + 1), arg); } else av[ac] = arg; } #if 0 { int k; printf("ParseLine: %d args:\n", ac); for (k = 0; k < ac; k++) printf(" [%2d] \"%s\"\n", k, av[k]); } #endif return(ac); } /* * FreeArgs() */ void FreeArgs(int ac, char *av[]) { while (ac > 0) Freee(MB_CMD, av[--ac]); } /* * Escape() * * Give a string, interpret the beginning characters as an escape * code and return with that code converted. */ static void Escape(char *line) { int x, k; char *s = line; switch (*line) { case 't': *s = '\t'; return; case 'n': *s = '\n'; return; case 'r': *s = '\r'; return; case 's': *s = ' '; return; case '"': *s = '"'; return; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': for (x = k = 0; k < 3 && *s >= '0' && *s <= '7'; s++) x = (x << 3) + (*s - '0'); *--s = x; break; case 'x': for (s++, x = k = 0; k < 2 && isxdigit(*s); s++) x = (x << 4) + (isdigit(*s) ? (*s - '0') : (tolower(*s) - 'a' + 10)); *--s = x; break; default: return; } strcpy(line, s); } /* * ReadFile() * * Read the commands specified for the target in the specified * file, which can be found in the PATH_CONF_DIR directory. * Returns negative if the file or target was not found. */ int ReadFile(const char *filename, const char *target, int (*func)(int ac, char *av[], const char *file, int line)) { FILE *fp; int ac; char *av[MAX_LINE_ARGS]; char *line; char buf[BIG_LINE_SIZE]; struct configfile *cf; int lineNum; /* Open file */ if ((fp = OpenConfFile(filename, &cf)) == NULL) return(-1); /* Find label */ if (SeekToLabel(fp, target, &lineNum, cf) < 0) { fclose(fp); return(-1); } /* Execute command list */ while ((line = ReadFullLine(fp, &lineNum, buf, sizeof(buf))) != NULL) { if (!isspace(*line)) { break; } ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 0); (*func)(ac, av, filename, lineNum); } /* Done */ fclose(fp); return(0); } /* * IndexConfFile() * * Scan config file for labels */ static void IndexConfFile(FILE *fp, struct configfile **cf) { char *s, *line; char buf[BIG_LINE_SIZE]; struct configfile **tmp; int lineNum; /* Start at beginning */ rewind(fp); lineNum = 0; tmp=cf; /* Find label */ while ((line = ReadFullLine(fp, &lineNum, buf, sizeof(buf))) != NULL) { if (isspace(*line)) continue; if ((s = strtok(line, " \t\f:"))) { (*tmp)=Malloc(MB_CMDL, sizeof(struct configfile)); (*tmp)->label=strcpy(Malloc(MB_CMDL, strlen(s)+1),s); (*tmp)->linenum=lineNum; (*tmp)->seek=ftello(fp); tmp=&((*tmp)->next); } } } /* * SeekToLabel() * * Find a label in file and position file pointer just after it */ int SeekToLabel(FILE *fp, const char *label, int *lineNum, struct configfile *cf) { char *s, *line; char buf[BIG_LINE_SIZE]; struct configfile *tmp; if (cf) { /* Trying to use index */ tmp=cf; while (tmp && strcmp(tmp->label,label)) { tmp=tmp->next; } if (tmp) { fseeko(fp,tmp->seek, SEEK_SET); if (lineNum) *lineNum=tmp->linenum; return(0); } } else { /* There are no index */ /* Start at beginning */ rewind(fp); if (lineNum) *lineNum = 0; /* Find label */ while ((line = ReadFullLine(fp, lineNum, buf, sizeof(buf))) != NULL) { if (isspace(*line)) continue; if ((s = strtok(line, " \t\f:")) && !strcmp(s, label)) return(0); } } /* Not found */ Log(LG_ERR, ("Label '%s' not found", label)); return(-1); } /* * OpenConfFile() * * Open a configuration file */ FILE * OpenConfFile(const char *name, struct configfile **cf) { char pathname[MAX_FILENAME]; FILE *fp; struct configfiles **tmp; /* Build full pathname */ snprintf(pathname, sizeof(pathname), "%s/%s", gConfDirectory, name); /* Open file */ if ((fp = fopen(pathname, "r")) == NULL) { Perror("%s: Can't open file '%s'", __FUNCTION__, pathname); return(NULL); } (void) fcntl(fileno(fp), F_SETFD, 1); if (cf) { tmp=&ConfigFilesIndex; while ((*tmp) && strcmp((*tmp)->filename,name)) { tmp=&((*tmp)->next); } if (!(*tmp)) { (*tmp) = Malloc(MB_CMD, sizeof(struct configfiles)); (*tmp)->filename = strcpy(Malloc(MB_CMD, strlen(name)+1),name); (*tmp)->sections = NULL; (*tmp)->next = NULL; IndexConfFile(fp, &((*tmp)->sections)); } *cf=(*tmp)->sections; } return(fp); } /* * ReadFullLine() * * Read a full line, respecting backslash continuations. * Returns pointer to Malloc'd storage, which must be Freee'd */ char * ReadFullLine(FILE *fp, int *lineNum, char *result, int resultsize) { int len, linelen, resultlinesize, continuation; char line[BIG_LINE_SIZE]; char real_line[BIG_LINE_SIZE]; char *resultline; if (result!=NULL && resultsize>0) { resultline=result; resultlinesize=resultsize; } else { resultline=line; resultlinesize=sizeof(line); } resultline[0] = 0; linelen = 0; continuation = TRUE; while ( continuation ) { /* Get next real line */ if (ReadLine(fp, lineNum, real_line, sizeof(real_line)) == NULL) { if (*resultline) break; else return(NULL); } /* Strip trailing white space, detect backslash */ for (len = strlen(real_line); len > 0 && isspace(real_line[len - 1]); len--) {}; real_line[len] = 0; if ((continuation = (len && real_line[len - 1] == '\\'))) real_line[len - 1] = ' '; /* Append real line to what we've got so far */ snprintf(resultline + linelen, resultlinesize - linelen, "%s", real_line); linelen += len; if (linelen > sizeof(line) - 1) linelen = sizeof(line) - 1; } /* Report any overflow */ if (linelen >= sizeof(line) - 1) Log(LG_ERR, ("warning: line too long, truncated")); /* Copy line and return */ if (result!=NULL && resultsize>0) return resultline; else return strcpy(Malloc(MB_CMD, linelen + 1), resultline); } /* * ReadLine() * * Read a line, skipping blank lines & comments. A comment * is a line whose first non-white-space character is a hash. */ static char * ReadLine(FILE *fp, int *lineNum, char *result, int resultsize) { int empty; char ch, *s; if ((!result) || (resultsize <= 0)) return (NULL); /* Get first non-empty, non-commented line */ empty = TRUE; while ( empty ) { /* Read next line from file */ if ((fgets(result, resultsize, fp)) == NULL) return(NULL); if (lineNum) (*lineNum)++; /* Truncate long lines */ if (strlen(result) > (resultsize - 2)) { Log(LG_ERR, ("warning: line too long, truncated")); while ((ch = getc(fp)) != EOF && ch != '\n'); } /* Ignore comments */ s = result + strspn(result, " \t"); if (*s == '#') { *s = 0; } else { /* Is this line empty? */ for ( ; *s; s++) { if (!isspace(*s)) { empty = FALSE; break; } } } } return(result); } /* * OpenSerialDevice() * * Open and configure a serial device. Call ExclusiveCloseDevice() * to close a file descriptor returned by this function. */ int OpenSerialDevice(const char *path, int baudrate) { struct termios attr; int fd; /* Open & lock serial port */ if ((fd = ExclusiveOpenDevice(path)) < 0) return(-1); /* Set non-blocking I/O */ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { Log(LG_ERR, ("[%s] can't set \"%s\" to non-blocking: %s", lnk->name, path, strerror(errno))); goto failed; } /* Set serial port raw mode, baud rate, hardware flow control, etc. */ if (tcgetattr(fd, &attr) < 0) { Log(LG_ERR, ("[%s] can't tcgetattr \"%s\": %s", lnk->name, path, strerror(errno))); goto failed; } cfmakeraw(&attr); attr.c_cflag &= ~(CSIZE|PARENB|PARODD); attr.c_cflag |= (CS8|CREAD|CLOCAL|HUPCL|CCTS_OFLOW|CRTS_IFLOW); attr.c_iflag &= ~(IXANY|IMAXBEL|ISTRIP|IXON|IXOFF|BRKINT|ICRNL|INLCR); attr.c_iflag |= (IGNBRK|IGNPAR); attr.c_oflag &= ~OPOST; attr.c_lflag = 0; cfsetspeed(&attr, (speed_t) baudrate); if (tcsetattr(fd, TCSANOW, &attr) < 0) { Log(LG_ERR, ("[%s] can't tcsetattr \"%s\": %s", lnk->name, path, strerror(errno))); failed: ExclusiveCloseDevice(fd, path); return(-1); } /* OK */ return(fd); } /* * ExclusiveOpenDevice() */ int ExclusiveOpenDevice(const char *pathname) { int fd, locked = FALSE; const char *ttyname = NULL; time_t startTime; /* Lock device UUCP style, if it resides in /dev */ if (!strncmp(pathname, "/dev/", 5)) { ttyname = pathname + 5; if (UuLock(ttyname) < 0) { Log(LG_ERR, ("[%s] can't lock device %s", lnk->name, ttyname)); return(-1); } locked = TRUE; } /* Open it, but give up after so many interruptions */ for (startTime = time(NULL); (fd = open(pathname, O_RDWR, 0)) < 0 && time(NULL) < startTime + MAX_OPEN_DELAY; ) if (errno != EINTR) { Log(LG_ERR, ("[%s] can't open %s: %s", lnk->name, pathname, strerror(errno))); if (locked) UuUnlock(ttyname); return(-1); } /* Did we succeed? */ if (fd < 0) { Log(LG_ERR, ("[%s] can't open %s after %d secs", lnk->name, pathname, MAX_OPEN_DELAY)); if (locked) UuUnlock(ttyname); return(-1); } (void) fcntl(fd, F_SETFD, 1); /* Done */ return(fd); } /* * ExclusiveCloseDevice() */ void ExclusiveCloseDevice(int fd, const char *pathname) { int rtn = -1; const char *ttyname; time_t startTime; /* Close file(s) */ for (startTime = time(NULL); time(NULL) < startTime + MAX_OPEN_DELAY && (rtn = close(fd)) < 0; ) if (errno != EINTR) { Log(LG_ERR, ("[%s] can't close %s: %s", lnk->name, pathname, strerror(errno))); break; } /* Did we succeed? */ if ((rtn < 0) && (errno == EINTR)) { Log(LG_ERR, ("[%s] can't close %s after %d secs", lnk->name, pathname, MAX_OPEN_DELAY)); DoExit(EX_ERRDEAD); } /* Remove lock */ if (!strncmp(pathname, "/dev/", 5)) { ttyname = pathname + 5; if (UuUnlock(ttyname) < 0) Log(LG_ERR, ("[%s] can't unlock %s: %s", lnk->name, ttyname, strerror(errno))); } } /* * UuLock() * * Try to atomically create lockfile. Returns negative if failed. */ static int UuLock(const char *ttyname) { int fd, pid; char tbuf[sizeof(PATH_LOCKFILENAME) + MAX_FILENAME]; char pid_buf[64]; snprintf(tbuf, sizeof(tbuf), PATH_LOCKFILENAME, ttyname); if ((fd = open(tbuf, O_RDWR|O_CREAT|O_EXCL, 0664)) < 0) { /* File is already locked; Check to see if the process * holding the lock still exists */ if ((fd = open(tbuf, O_RDWR, 0)) < 0) { Perror("%s: open(%s)", __FUNCTION__, tbuf); return(-1); } if (read(fd, pid_buf, sizeof(pid_buf)) <= 0) { (void)close(fd); Perror("%s: read", __FUNCTION__); return(-1); } pid = atoi(pid_buf); if (kill(pid, 0) == 0 || errno != ESRCH) { (void)close(fd); /* process is still running */ return(-1); } /* The process that locked the file isn't running, so we'll lock it */ if (lseek(fd, (off_t) 0, L_SET) < 0) { (void)close(fd); Perror("%s: lseek", __FUNCTION__); return(-1); } } /* Finish the locking process */ sprintf(pid_buf, "%10u\n", (int) gPid); if (write(fd, pid_buf, strlen(pid_buf)) != strlen(pid_buf)) { (void)close(fd); (void)unlink(tbuf); Perror("%s: write", __FUNCTION__); return(-1); } (void)close(fd); return(0); } /* * UuUnlock() */ static int UuUnlock(const char *ttyname) { char tbuf[sizeof(PATH_LOCKFILENAME) + MAX_FILENAME]; (void) sprintf(tbuf, PATH_LOCKFILENAME, ttyname); return(unlink(tbuf)); } /* * WriteMbuf() * * Write an mbuf to a file descriptor which is character based. * Leave whatever portion of the mbuf is remaining. */ int WriteMbuf(Mbuf *mp, int fd, const char *label) { while (*mp) { Mbuf const bp = *mp; int nw; if ((nw = write(fd, MBDATA(bp), MBLEN(bp))) < 0) { if (errno == EAGAIN) return(0); Log(LG_ERR, ("[%s] %s write: %s", lnk->name, label, strerror(errno))); return(-1); } bp->offset += nw; bp->cnt -= nw; if (bp->cnt != 0) break; *mp = mbfree(bp); } return(0); } /* * GenerateMagic() * * Generate random number which will be used as magic number. * This could be made a little more "random"... */ u_long GenerateMagic(void) { time_t now; struct timeval tval; time(&now); gettimeofday(&tval, NULL); now += (tval.tv_sec ^ tval.tv_usec) + getppid(); now *= gPid; return(now); } /* * PIDCheck() * * See if process is already running and deal with PID file. */ int PIDCheck(const char *filename, int killem) { int fd = -1, n_tries; /* Sanity */ assert(!lockFp); /* Atomically open and lock file */ for (n_tries = 0; n_tries < MAX_LOCK_ATTEMPTS && (fd = open(filename, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644)) < 0; n_tries++) { int nscan, old_pid; FILE *fp; /* Abort on any unexpected errors */ if (errno != EAGAIN) { Perror("%s: open(%s)", __FUNCTION__, filename); return(-1); } /* We're already running ... see who it is */ if ((fp = fopen(filename, "r")) == NULL) { Perror("%s: fopen(%s)", __FUNCTION__, filename); return(-1); } /* If there's a PID in there, sniff it out */ nscan = fscanf(fp, "%d", &old_pid); fclose(fp); if (nscan != 1) { Log(LG_ERR, ("%s: contents mangled", filename)); return(-1); } /* Maybe kill the other guy */ if (!killem) { Log(LG_ERR, ("already running as process %d", old_pid)); return(-1); } if (kill(old_pid, SIGTERM) < 0) switch (errno) { case ESRCH: Log(LG_ERR, ("process %d no longer exists", old_pid)); break; default: Perror("%s: kill(%d)", __FUNCTION__, old_pid); return(-1); } /* Wait and try again */ Log(LG_ERR, ("waiting for process %d to die...", old_pid)); sleep(1); } if (n_tries == MAX_LOCK_ATTEMPTS) { Log(LG_ERR, ("can't lock %s after %d attempts", filename, n_tries)); return(-1); } /* Close on exec */ (void) fcntl(fd, F_SETFD, 1); /* Create a stream on top of file descriptor */ if ((lockFp = fdopen(fd, "r+")) == NULL) { Perror("%s: fdopen", __FUNCTION__); return(-1); } setbuf(lockFp, NULL); /* Write my PID in there */ rewind(lockFp); fprintf(lockFp, "%u\n", (u_int) gPid); fflush(lockFp); (void) ftruncate(fileno(lockFp), ftell(lockFp)); return(0); } /* * GetInetSocket() * * Get a TCP socket and bind it to an address. Set SO_REUSEADDR on the socket. */ int GetInetSocket(int type, struct u_addr *addr, in_port_t port, int block, char *ebuf, int len) { int sock; static int one = 1; struct sockaddr_storage sa; u_addrtosockaddr(addr,port,&sa); /* Get and bind non-blocking socket */ if ((sock = socket(sa.ss_family, type, type == SOCK_STREAM ? IPPROTO_TCP : 0)) < 0) { snprintf(ebuf, len, "socket: %s", strerror(errno)); return(-1); } (void) fcntl(sock, F_SETFD, 1); if (!block) { if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { snprintf(ebuf, len, "can't set socket non-blocking: %s", strerror(errno)); close(sock); return(-1); } } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { snprintf(ebuf, len, "setsockopt: %s", strerror(errno)); close(sock); return(-1); } if (bind(sock, (struct sockaddr *) &sa, sa.ss_len) < 0) { snprintf(ebuf, len, "bind: %s", strerror(errno)); close(sock); return(-1); } return(sock); } /* * TcpGetListenPort() * * Get port for incoming telnet connections */ int TcpGetListenPort(struct u_addr *addr, in_port_t port, int block) { char ebuf[100]; int sock; int saverrno; /* Get socket */ if ((sock = GetInetSocket(SOCK_STREAM, addr, port, block, ebuf, sizeof(ebuf))) < 0) { saverrno = errno; Log(LG_ERR, ("%s", ebuf)); errno = saverrno; return(-1); } /* Make socket available for connections */ if (listen(sock, 2) < 0) { Perror("%s: listen", __FUNCTION__); (void) close(sock); return(-1); } /* Done */ return(sock); } /* * TcpAcceptConnection() * * Accept next connection on port */ int TcpAcceptConnection(int sock, struct sockaddr_storage *addr, int block) { int new_sock; socklen_t size=sizeof(struct sockaddr_storage); struct request_info req; /* Accept incoming connection */ memset(addr, 0, sizeof(*addr)); if ((new_sock = accept(sock, (struct sockaddr *) addr, &size)) < 0) { Perror("%s: accept", __FUNCTION__); return(-1); } if (bund) { if (Enabled(&gGlobalConf.options, GLOBAL_CONF_TCPWRAPPER)) { request_init(&req, RQ_DAEMON, "mpd", RQ_FILE, new_sock, NULL); fromhost(&req); if (!hosts_access(&req)) { Log(LG_ERR, ("[%s] refused connection (tcp-wrapper) from %s", bund->name, eval_client(&req))); close(new_sock); return(-1); } } } if (!block) { (void) fcntl(new_sock, F_SETFD, 1); if (fcntl(new_sock, F_SETFL, O_NONBLOCK) < 0) { Perror("%s: fcntl", __FUNCTION__); return(-1); } } /* Done */ return(new_sock); } /* * ShowMesg() */ void ShowMesg(int log, const char *buf, int len) { char *s, mesg[256]; if (len > 0) { if (len > sizeof(mesg) - 1) len = sizeof(mesg) - 1; memcpy(mesg, buf, len); mesg[len] = 0; for (s = strtok(mesg, "\r\n"); s; s = strtok(NULL, "\r\n")) Log(log, (" MESG: %s", s)); } } /* * Bin2Hex() */ char * Bin2Hex(const unsigned char *bin, int len) { static char hexconvtab[] = "0123456789abcdef"; int i, j; char *buf; buf = Malloc(MB_UTIL, len * 2 + 1); for (i = j = 0; i < len; i++) { buf[j++] = hexconvtab[bin[i] >> 4]; buf[j++] = hexconvtab[bin[i] & 15]; } buf[j] = 0; return buf; } /* * Hex2Bin() */ u_char * Hex2Bin(char *hexstr) { int i; u_char *binval; binval = Malloc(MB_UTIL, strlen(hexstr) / 2); for (i = 0; i < strlen(hexstr) / 2; i++) { binval[i] = 16 * HexVal(hexstr[2*i]) + HexVal(hexstr[2*i+1]); } return binval; } static char HexVal(char c) { if (c >= '0' && c <= '9') { return (c - '0'); } else if (c >= 'a' && c <= 'z') { return (c - 'a' + 10); } else if (c >= 'A' && c <= 'Z') { return (c - 'A' + 10); } else { return (-1); } } /* * Crc16() * * Compute the 16 bit frame check value, per RFC 1171 Appendix B, * on an array of bytes. */ u_short Crc16(u_short crc, u_char *cp, int len) { while (len--) crc = (crc >> 8) ^ Crc16Table[(crc ^ *cp++) & 0xff]; return(crc); } static const u_int16_t Crc16Table[256] = { /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; /* * GetAnyIpAddress() * * Get any non-loopback IP address owned by this machine * Prefer addresses from non-point-to-point interfaces. */ int GetAnyIpAddress(struct u_addr *ipaddr, const char *ifname) { int s, p2p = 0; struct in_addr ipa = { 0 }; struct ifreq *ifr, *ifend; struct ifreq ifreq; struct ifconf ifc; struct ifreq ifs[MAX_INTERFACES]; /* Get interface list */ if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { Perror("%s: Socket creation error", __FUNCTION__); return(-1); } ifc.ifc_len = sizeof(ifs); ifc.ifc_req = ifs; if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__); close(s); return(-1); } for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len), ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)(void *)((char *) &ifr->ifr_addr + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) { if (ifr->ifr_addr.sa_family == AF_INET) { if (ifname!=NULL && strcmp(ifname,ifr->ifr_name)) continue; /* Check that the interface is up; prefer non-p2p and non-loopback */ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) continue; if ((ifreq.ifr_flags & IFF_UP) != IFF_UP) continue; if ((ifreq.ifr_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) && ipa.s_addr) continue; if ((ntohl(((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr.s_addr)>>24)==127) continue; /* Save IP address and interface name */ ipa = ((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr; p2p = (ifreq.ifr_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0; if (!p2p) break; } } close(s); /* Found? */ if (ipa.s_addr == 0) return(-1); in_addrtou_addr(&ipa, ipaddr); return(0); } /* * GetEther() * * Get the hardware address of an interface on the the same subnet as addr. * If addr == NULL, finds the address of any local ethernet interface. */ int GetEther(struct u_addr *addr, struct sockaddr_dl *hwaddr) { int s; struct ifreq *ifr, *ifend, *ifp; u_int32_t ina, mask; struct ifreq ifreq; struct ifconf ifc; struct ifreq ifs[MAX_INTERFACES]; /* Get interface list */ if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { Perror("%s: Socket creation error", __FUNCTION__); return(-1); } ifc.ifc_len = sizeof(ifs); ifc.ifc_req = ifs; if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { Perror("%s: ioctl(SIOCGIFCONF)", __FUNCTION__); close(s); return(-1); } /* * Scan through looking for an interface with an IP * address on same subnet as `addr'. */ for (ifend = (struct ifreq *)(void *)(ifc.ifc_buf + ifc.ifc_len), ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)(void *)((char *) &ifr->ifr_addr + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) { if (ifr->ifr_addr.sa_family == AF_INET) { /* Save IP address and interface name */ ina = ((struct sockaddr_in *)(void *)&ifr->ifr_addr)->sin_addr.s_addr; strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); ifreq.ifr_addr = ifr->ifr_addr; /* Check that the interface is up, and not point-to-point or loopback */ if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) continue; if ((ifreq.ifr_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) continue; /* Get its netmask and check that it's on the right subnet */ if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) continue; mask = ((struct sockaddr_in *)(void *)&ifreq.ifr_addr)->sin_addr.s_addr; if (addr && (addr->u.ip4.s_addr & mask) != (ina & mask)) continue; /* OK */ break; } } close(s); /* Found? */ if (ifr >= ifend) return(-1); /* Now scan again looking for a link-level address for this interface */ for (ifp = ifr, ifr = ifc.ifc_req; ifr < ifend; ) { if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 && ifr->ifr_addr.sa_family == AF_LINK) { memcpy(hwaddr, (struct sockaddr_dl *)(void *)&ifr->ifr_addr, sizeof(*hwaddr)); return(0); } ifr = (struct ifreq *)(void *)((char *)&ifr->ifr_addr + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr))); } /* Not found! */ return(-1); } /* * Decode ASCII message */ void ppp_util_ascify(char *buf, size_t bsiz, const u_char *data, size_t len) { char *bp = buf; int i; for (bp = buf, i = 0; i < len; i++) { const char ch = (char)data[i]; if (bsiz < 3) break; switch (ch) { case '\t': *bp++ = '\\'; *bp++ = 't'; bsiz -= 2; break; case '\n': *bp++ = '\\'; *bp++ = 'n'; bsiz -= 2; break; case '\r': *bp++ = '\\'; *bp++ = 'r'; bsiz -= 2; break; default: if (isprint(ch & 0x7f)) { *bp++ = ch; bsiz--; } else { *bp++ = '^'; *bp++ = '@' + (ch & 0x1f); bsiz -= 2; } break; } } *bp = '\0'; }