DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T f

⟦3db57d61a⟧ TextFile

    Length: 5501 (0x157d)
    Types: TextFile
    Names: »fromhost.c«

Derivation

└─⟦4f9d7c866⟧ Bits:30007245 EUUGD6: Sikkerheds distributionen
    └─⟦62b59102f⟧ »./log_tcp/3.1.tar.Z« 
        └─⟦1de3ed35f⟧ 
            └─⟦this⟧ »log_tcp/fromhost.c« 

TextFile

 /*
  * 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