home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
lan
/
nameserv
/
nameserv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-10-17
|
14KB
|
506 lines
#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 */
}