home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume23
/
log_tcp
/
part01
/
fromhost.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-19
|
6KB
|
217 lines
/*
* fromhost() returns the type of connection (datagram, stream) and the name
* of the host at the other end of standard input (the host address if host
* name lookup fails, "stdin" if it is connected to a terminal, or "unknown"
* in all other cases). The return status is (-1) if the remote host
* pretends to have someone elses host name, otherwise a zero status is
* returned.
*
* Diagnostics are reported through syslog(3).
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) fromhost.c 1.4 91/10/02 23:01:46";
#endif
/* System libraries. */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <syslog.h>
#include <errno.h>
extern char *inet_ntoa();
extern char *strncpy();
extern char *strcpy();
/* Local stuff. */
#include "log_tcp.h"
/* Forward declarations. */
static int matchname();
/* The following are to be used in assignment context, not in comparisons. */
#define GOOD 1
#define BAD 0
/*
* The apollo sr10.3 getpeername(2) does not return an error in case of a
* datagram-oriented socket. Instead, it claims that all UDP or RPC requests
* come from address 0.0.0.0. The following code works around the problem.
*/
#ifdef GETPEERNAME_BUG
static int fix_getpeername(sock, sa, len)
int sock;
struct sockaddr *sa;
int *len;
{
int ret;
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
if ((ret = getpeername(sock, sa, len)) >= 0
&& sa->sa_family == AF_INET
&& strcmp(inet_ntoa(sin->sin_addr), "0.0.0.0") == 0) {
errno = ENOTCONN;
return (-1);
} else {
return (ret);
}
}
#define getpeername fix_getpeername
#endif
/* fromhost - find out what is at the other end of standard input */
int fromhost(f)
struct from_host *f;
{
struct sockaddr sa;
struct sockaddr_in *sin = (struct sockaddr_in *) (&sa);
struct hostent *hp;
int length = sizeof(sa);
char buf[BUFSIZ];
/*
* Look up the remote host address. Hal R. Brand <BRAND@addvax.llnl.gov>
* suggested how to get the remote host info in case of UDP connections:
* peek at the first message without actually looking at its contents.
*/
#define punt(name) { f->sock_type = 0; strcpy(f->source, name); return(0); }
if (getpeername(0, &sa, &length) >= 0) { /* assume TCP request */
f->sock_type = FROM_CONNECTED;
} else {
switch (errno) {
case ENOTSOCK: /* stdin is not a socket */
punt(isatty(0) ? "stdin" : "unknown");
case ENOTCONN: /* assume UDP request */
if (recvfrom(0, buf, sizeof(buf), MSG_PEEK, &sa, &length) < 0) {
syslog(LOG_ERR, "recvfrom: %m");
punt("unknown");
}
f->sock_type = FROM_UNCONNECTED;
break;
default: /* other, punt */
syslog(LOG_ERR, "getpeername: %m");
punt("unknown");
}
}
/*
* Now that we have the remote host address, look up the remote host
* name. Use the address if name lookup fails. At present, we can only
* handle names or addresses that belong to the AF_INET addres family.
*/
if (sa.sa_family != AF_INET) {
syslog(LOG_ERR, "unexpected address family %ld", (long) sa.sa_family);
strcpy(f->source, "unknown");
return (0);
}
if ((hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
sizeof(sin->sin_addr.s_addr),
AF_INET)) == 0) {
strcpy(f->source, inet_ntoa(sin->sin_addr)); /* use address */
return (0);
}
/*
* Save the host name, even if we may decide to not use it, because the
* next gethostbyxxx() call will clobber it.
*/
strncpy(f->source, hp->h_name, sizeof(f->source) - 1);
f->source[sizeof(f->source) - 1] = 0;
/*
* Verify that the host name does not belong to someone else. If host
* name verification fails, ignore the host name and use the address
* instead.
*/
if (matchname(f->source, sin)) {
return (0);
} else {
strcpy(f->source, inet_ntoa(sin->sin_addr));
return (-1); /* verification failed */
}
}
/* matchname - determine if host name matches IP address */
static int matchname(remotehost, sin)
char *remotehost;
struct sockaddr_in *sin;
{
struct hostent *hp;
int i;
if ((hp = gethostbyname(remotehost)) == 0) {
/*
* Unable to verify that the host name matches the address. This may
* be a transient problem or a botched name server setup. We decide
* to play safe.
*/
syslog(LOG_ERR, "gethostbyname(%s): lookup failure", remotehost);
return (BAD);
} else {
/* Look up the host address in the address list we just got. */
for (i = 0; hp->h_addr_list[i]; i++) {
if (memcmp(hp->h_addr_list[i],
(caddr_t) & sin->sin_addr,
sizeof(sin->sin_addr)) == 0)
return (GOOD);
}
/*
* The host name does not map to the original host address. Perhaps
* someone has compromised a name server. More likely someone botched
* it, but that could be dangerous, too.
*/
syslog(LOG_ERR, "host name/address mismatch: %s != %s",
inet_ntoa(sin->sin_addr), hp->h_name);
return (BAD);
}
}
#ifdef TEST
/* Code for stand-alone testing. */
main(argc, argv)
int argc;
char **argv;
{
struct from_host from;
#ifdef LOG_MAIL
(void) openlog(argv[0], LOG_PID, FACILITY);
#else
(void) openlog(argv[0], LOG_PID);
#endif
(void) fromhost(&from);
printf("%s\n", from.source);
return (0);
}
#endif