home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *RCSid = "$Header: nameserver.c,v 2.3.1 88/02/26 jerry Rel $";
- #endif
-
- /* nameserver --
- Use the IEN 116 protocol to respond to nameserver requests.
-
- Modified by Jerry Aguirre. 21Mar1988
- Count in header does not include header bytes. Added a "glob"
- capability so "*" returns all host names. Removed fatal abort if no
- tty so daemon can be started from rc.local.
-
- Written by Michael I. Bushnell.
- Copyright (c) 1987 Michael I. Bushnell
- You are hereby granted permission to use this program however you wish,
- including copying and distribution. However, you are obligated not to sell
- it or any part of it. Anyone who obtains this program receives the right
- to do the same. This statement may not be removed from this program.
- */
-
- /*
- * $Source: /u1/staff/mike/src/nameserver/RCS/nameserver.c,v $
- * $Revision: 2.3 $
- * $Date: 87/06/24 15:02:59 $
- * $State: Rel $
- * $Author: mike $
- * $Locker: $
- * $Log: nameserver.c,v $
- * Revision 2.3.1 88/02/26 Jerry Aguirre
- * Modified to work with Bridge terminal server version 1300. The field
- * size doesn't include the 2 byte header. Also added a glob capability
- * so '*' or 'xyz*' works. The '*' may not return all hosts because the
- * sendto limits the size I can send.
- *
- * Revision 2.3 87/06/24 15:02:59 mike
- * Final preparations for release. Addeed Copyright.
- *
- * Revision 2.2 87/06/24 14:54:29 mike
- * de-lintified. Lint, stupidly, doesn't pick up the definition of h_errno f
- * from libc.a. Sigh. Prepared for release.
- *
- * Revision 2.1 87/06/24 14:48:14 mike
- * Better comments.
- *
- * Revision 2.0 87/06/23 16:55:03 mike
- * Split it up into different functions.
- *
- * Revision 1.9 87/06/23 16:14:09 mike
- * Added stuff to divorce process from shell and control terminal.
- *
- * Revision 1.8 87/06/19 16:59:36 mike
- * Uses syslog instead of perror.
- * Lots of symbolic constants.
- *
- * Revision 1.7 87/06/19 14:43:49 mike
- * Fixed bug... need to initialize addrlen to sizeof(hisname).
- *
- * Revision 1.6 87/06/16 16:08:04 mike
- * Changed all "sizeof (hisaddr)" to "addrlen."
- * Still a bug...the last sendto is returning EINVAL???
- *
- * Revision 1.5 87/06/16 15:57:07 mike
- * Actually...you need to return the raw bytes. So I changed it back.
- * Also added bookoo error checking.
- *
- * Revision 1.4 87/06/15 13:50:22 mike
- * Fixed bug...need to cast the argument of inet_ntoa into a struct in_addr.
- *
- * Revision 1.3 87/06/08 14:16:56 mike
- * Uses a PORT number instead of system chosen default...now its 5001.
- *
- * Revision 1.2 87/06/08 14:10:33 mike
- * Now it compiles.
- *
- * Revision 1.1 87/06/08 13:42:20 mike
- * Initial revision
- *
- */
-
- #include <sys/file.h>
- #include <sgtty.h>
-
- #include <signal.h>
- #include <syslog.h>
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
-
- #include <stdio.h>
- #include <ctype.h>
-
- #include "ien116.h"
-
- /* Generic constants */
- #define BUFLEN 512 /* Length of I/O buffers */
- #define RBUFLEN 1400 /* Length of glob reply buffer */
- /* note that there is a limit on size of sendto */
- #define DEF_PROTO 0 /* Use default protocol */
- #define NO_FLAGS 0 /* No flags on recvfrom/sendto */
-
- /* Message lengths */
- #define RET_MSG_LEN 6 /* Length of what we add to buf */
- #define ERR_MSG_LEN 3 /* Length of error messages */
-
- char buf[BUFLEN]; /* Input/Output buffer */
- extern int errno, h_errno;
- extern char *sys_errlist[];
-
- int debug;
-
- main(argc, argv) int argc; char *argv[];
- {
- int sock; /* Datagram socket */
- struct sockaddr_in hisname; /* Address of requestor */
- int addrlen; /* Length of his address */
- struct hostent *hp, *gethostbyname(); /* Host inquired of */
- char *name; /* Name of the machine requested */
- int msglen; /* Length of the message received */
- char *nameloc();
- int arg, i;
-
- for (arg = 1; arg < argc; arg++) {
- if (argv[arg][0] == '-') {
- for (i = 1; argv[arg][i]; i++) {
- switch (argv[arg][i]) {
- case 'd':
- if (isdigit(argv[arg][i+1])) {
- debug = atoi(&argv[arg][i+1]);
- break;
- } else debug = 1;
- continue;
-
- default:
- fprintf(stderr, "nameserver: unknown option \'-%c\'.\n",
- argv[arg][i]);
- }
- break;
- }
- } else {
- fprintf(stderr, "nameserver: unexpected argument \"%s\".\n",
- argv[arg]);
- }
- }
-
- if (!debug) setupsig(); /* Set up signal handling */
- setuplog(); /* Set up the syslog connection */
- if (!debug) divorce(); /* Divorce ourselves from terminal and shell */
- sock = makesocket(); /* make and bind the socket */
-
- addrlen = sizeof(hisname);
-
- /* Main loop */
- restart:
- while (1)
- {
- /* Read a message */
- msglen = recvfrom(sock, buf, BUFLEN - RET_MSG_LEN,
- NO_FLAGS, (struct sockaddr *)&hisname, &addrlen);
- if (debug) fprintf(stderr, "nameserver: got a request\n");
- if (msglen == -1)
- {
- syslog(LOG_ERR, "Error on incoming message: %s\n",
- sys_errlist[errno]);
- if (debug) fprintf(stderr, "Error on incoming message: %s\n",
- sys_errlist[errno]);
- goto restart;
- }
-
- /* Find the name */
- name = nameloc(buf, BUFLEN, msglen, &hisname, addrlen, sock);
- if ((int) name == -1) {
- if (debug) fprintf(stderr, "nameserver: namelog() returned -1\n");
- goto restart;
- }
-
- if (isglob(name)) {
- if (debug) fprintf(stderr, "nameserver: looking up pattern \"%s\".\n",
- name);
- doglob(name, &hisname, addrlen, sock);
- goto restart;
- }
-
- if (debug) fprintf(stderr, "nameserver: looking up host \"%s\".\n",
- name);
- /* Get the host entry */
- if ((hp = gethostbyname(name))== NULL)
- {
- /* Send error message */
- buf[msglen] = ERR;
- buf[msglen+1] = ERR_MSG_LEN - 2;
- if (h_errno == HOST_NOT_FOUND ||
- h_errno == TRY_AGAIN ||
- h_errno == NO_ADDRESS)
- buf[msglen+2] = HOST_UNK;
- else
- buf[msglen+2] = UNK_ERR;
- if (sendto(sock, buf, msglen+ERR_MSG_LEN, NO_FLAGS,
- (struct sockaddr *)&hisname, addrlen)==-1)
- {
- syslog(LOG_ERR, "Error sending error 3: %s\n", sys_errlist[errno]);
- goto restart;
- }
- }
- else
- {
- /* Send the reply */
- buf[msglen] = ADDR_ANS;
- buf[msglen+1] = RET_MSG_LEN - 2;
- buf[msglen+2] = hp->h_addr_list[0][0];
- buf[msglen+3] = hp->h_addr_list[0][1];
- buf[msglen+4] = hp->h_addr_list[0][2];
- buf[msglen+5] = hp->h_addr_list[0][3];
-
- if (debug) fprintf(stderr, "nameserver: return IP %d.%d.%d.%d\n",
- hp->h_addr_list[0][0] & 0xff,
- hp->h_addr_list[0][1] & 0xff,
- hp->h_addr_list[0][2] & 0xff,
- hp->h_addr_list[0][3] & 0xff);
-
- if (sendto(sock, buf, msglen+RET_MSG_LEN, NO_FLAGS,
- (struct sockaddr *)&hisname, addrlen)==-1)
- {
- syslog(LOG_ERR, "Error sending reply: %s\n", sys_errlist[errno]);
- goto restart;
- }
- }
- }
- }
-
-
- /* setupsig -- Set all signals to be ignored. Those which cannot be ignored
- will be left at the default. */
- setupsig()
- {
- int i; /* Index of signals */
-
- for (i=0; i < NSIG; ++i)
- (void) signal(i, SIG_IGN);
- }
-
-
- /* setuplog -- set up the syslog connection */
- setuplog()
- {
- openlog("nameserver", LOG_PID | LOG_CONS, LOG_DAEMON);
- }
-
-
- /* divorce -- Divorce ourselves from the terminal and the shell */
- divorce()
- {
- int term; /* Terminal filed */
-
- /* First the shell */
- switch(fork())
- {
- case -1:
- syslog(LOG_CRIT, "Cannot fork: %s\n", sys_errlist[errno]);
- exit(1);
- break;
- case 0:
- break;
- default:
- exit(0);
- break;
- }
-
- /* Now the files */
- /* POTENTIAL BUG-- ASSUMES THAT THE TERMINAL IS ONLY OPEN ON FILEDS 0,1,2 */
- (void) close (0);
- (void) close (1);
- (void) close (2);
- /* Now the terminal */
- /* if started from rc.local, crontab, etc. there is no tty */
- if ((term = open("/dev/tty", O_RDWR, 0)) >= 0)
- {
- if (ioctl(term, TIOCNOTTY, (char *) 0) == -1)
- {
- syslog(LOG_CRIT, "Cannot divorce from control terminal: %s\n",
- sys_errlist[errno]);
- exit(1);
- }
- (void) close(term);
- }
- }
-
-
- /* makesocket -- return the filed of a new bound socket */
- makesocket()
- {
- int sock; /* Socket */
- struct sockaddr_in ourname; /* Our name */
-
- /* create the socket */
- sock = socket(AF_INET, SOCK_DGRAM, DEF_PROTO);
- if (sock < 0)
- {
- syslog(LOG_CRIT, "Error opening socket: %s\n", sys_errlist[errno]);
- exit(1);
- }
- ourname.sin_family = AF_INET;
- ourname.sin_port = htons((u_short)PORT);
- ourname.sin_addr.s_addr = INADDR_ANY;
- if (bind(sock, &ourname, sizeof(ourname)))
-
- {
- syslog(LOG_CRIT, "Error binding socket: %s\n", sys_errlist[errno]);
- exit(1);
- }
- return sock;
- }
-
-
- /* nameloc -- return the address of a null-terminated string which is the
- name to be looked up. Report syntax errors to reportto through sock.
- If an error occurs, return (char *) -1. If an error occurs, buf will be
- changed. */
- char *
- nameloc(buf, buflen, msglen, reportto, addrlen, sock)
- char *buf; /* Buffer holding the request */
- int buflen, /* Length of the buffer */
- msglen, /* Length of the message in the buffer */
- sock, /* Socket for error replies */
- addrlen; /* Length of reportto */
- struct sockaddr_in *reportto; /* Who we report errors to */
- {
- char *name; /* Address of the name */
- int code; /* Type of request */
-
- buf[msglen] = '\0';
- /* Check type */
- code = buf[0];
- if (code != ADDR_REQ)
- if (code !=ADDR_ANS && code !=ERR)
- {
- /* Send error message */
- buf[0] = ERR;
- buf[1] = ERR_MSG_LEN - 2;
- buf[2] = SYNT_ERR;
- if (sendto(sock, buf, ERR_MSG_LEN, NO_FLAGS,
- (struct sockaddr *)&reportto, addrlen)==-1)
- {
- syslog(LOG_ERR, "Error sending error 0: %s\n", sys_errlist[errno]);
- return (char *) -1;
- }
- }
- else
- return (char *) -1;
-
- /* Put name at the start of a null-terminated string */
- if (buf[2]!='!')
- name=buf+2;
- else
- {
- for(name=buf+2; *name!='!'; ++name)
- if (name-buf >= buflen)
- {
- /* Send error packet */
- buf[0] = ERR;
- buf[1] = ERR_MSG_LEN - 2;
- buf[2] = SYNT_ERR;
- if (sendto(sock, buf, ERR_MSG_LEN, NO_FLAGS,
- (struct sockaddr *)&reportto, addrlen)==-1)
- {
- syslog(LOG_ERR, "Error sending error 1: %s\n",
- sys_errlist[errno]);
- return (char *) -1;
- }
- }
- for(++name; *name!='!'; ++name)
- if (name-buf >= buflen)
- {
- /* Send error packet */
- buf[0] = ERR;
- buf[1] = ERR_MSG_LEN - 2;
- buf[2] = SYNT_ERR;
- if (sendto(sock, buf, ERR_MSG_LEN, NO_FLAGS,
- (struct sockaddr *)&reportto, addrlen)==-1)
- {
- syslog(LOG_ERR, "Error sending error 2: %s\n",
- sys_errlist[errno]);
- return (char *) -1;
- }
- }
- ++name;
- }
- return name;
- }
-
- int
- isglob(s) char *s; /* true if string s has pattern characters */
- {
- while (*s) {
- switch (*s++) {
- case '*': return 1;
- }
- }
- return 0;
- }
-
- /* check all hosts against pattern 's'. To reduce clutter only the
- * primary host name is checked, aliases are ignored.
- */
- doglob(s, reportto, addrlen, sock)
- char *s; /* string containing pattern */
- struct sockaddr_in *reportto; /* Who we report errors to */
- int addrlen; /* Length of reportto */
- int sock; /* Socket for error replies */
- {
- struct hostent *hp, *gethostent();
- int i, l, n;
- char buf[RBUFLEN]; /* Output buffer */
-
- if (s[0] == '\0') { /* null pattern is illegal */
- reterror(ADDR_REQ, s, SYNT_ERR, reportto, addrlen, sock);
- return 0;
- }
- sethostent(1);
- i = 0; n = 0;
- while ((i < RBUFLEN) && (hp = gethostent())) {
- if (requ(s, hp->h_name)) { /* we found a match */
- n++;
- l = strlen(hp->h_name);
- if (l > 255) l = 255;
- if ((i + 2 + l + 2 + 4) >= RBUFLEN) break;
- buf[i++] = ADDR_REQ;
- buf[i++] = l;
- strncpy(buf+i, hp->h_name, l);
- i += l;
- buf[i++] = ADDR_ANS;
- buf[i++] = 4;
- buf[i++] = hp->h_addr_list[0][0];
- buf[i++] = hp->h_addr_list[0][1];
- buf[i++] = hp->h_addr_list[0][2];
- buf[i++] = hp->h_addr_list[0][3];
- }
- }
- endhostent();
- if (n == 0) {
- reterror(ADDR_REQ, s, HOST_UNK, reportto, addrlen, sock);
- return 1;
- }
- if (i > 0) {
- if (sendto(sock, buf, i, NO_FLAGS,
- (struct sockaddr *)reportto, addrlen)==-1) {
- syslog(LOG_ERR, "Error sending reply: %s\n", sys_errlist[errno]);
- return 0;
- }
- }
- return 1;
- }
-
- reterror(rcode, rs, ecode, reportto, addrlen, sock)
- int rcode; /* type of request containing error */
- char *rs; /* string for above request */
- int ecode; /* error code to return */
- struct sockaddr_in *reportto; /* Who we report errors to */
- int addrlen; /* Length of reportto */
- int sock; /* Socket for error replies */
- {
- int i;
- char buf[BUFLEN]; /* Output buffer */
-
- buf[0] = rcode;
- i = strlen(rs);
- if (i > 255) i = 255;
- buf[1] = i;
- strncpy(buf+2, rs, i);
- i += 2;
- buf[i++] = ERR;
- buf[i++] = 1;
- buf[i++] = ecode;
- if (sendto(sock, buf, i, NO_FLAGS,
- (struct sockaddr *)&reportto, addrlen)==-1) {
- syslog(LOG_ERR, "Error sending error %d: %s\n",
- ecode, sys_errlist[errno]);
- return 0;
- }
- return 1;
- }
-
- /* Compare pattern 'p' to string 's'. Pattern can contain '*'
- * characters that will match 0 or more characters in string. Otherwise
- * the strings are compared on a character by character basis. Returns
- * non-zero for a match.
- */
- int
- requ(p, s) register char *p, *s;
- {
- while (*p) {
- if (*p == '*') {
- do {
- if (requ(p+1, s)) return 1; /* match */
- } while (*s++);
- return 0; /* no match */
- }
- else if (*s == '\0') return 0; /* no match */
- else if (*p != *s) return 0; /* no match */
- p++; s++; /* they match so far */
- }
- if (*s) return 0; /* no match */
- return 1; /* reached end of both strings, match */
- }
-