home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume23 / log_tcp / part01 / fromhost.c < prev    next >
C/C++ Source or Header  |  1991-10-19  |  6KB  |  217 lines

  1.  /*
  2.   * fromhost() returns the type of connection (datagram, stream) and the name
  3.   * of the host at the other end of standard input (the host address if host
  4.   * name lookup fails, "stdin" if it is connected to a terminal, or "unknown"
  5.   * in all other cases). The return status is (-1) if the remote host
  6.   * pretends to have someone elses host name, otherwise a zero status is
  7.   * returned.
  8.   * 
  9.   * Diagnostics are reported through syslog(3).
  10.   * 
  11.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  12.   */
  13.  
  14. #ifndef lint
  15. static char sccsid[] = "@(#) fromhost.c 1.4 91/10/02 23:01:46";
  16. #endif
  17.  
  18. /* System libraries. */
  19.  
  20. #include <sys/types.h>
  21. #include <sys/param.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <netdb.h>
  25. #include <stdio.h>
  26. #include <syslog.h>
  27. #include <errno.h>
  28.  
  29. extern char *inet_ntoa();
  30. extern char *strncpy();
  31. extern char *strcpy();
  32.  
  33. /* Local stuff. */
  34.  
  35. #include "log_tcp.h"
  36.  
  37. /* Forward declarations. */
  38.  
  39. static int matchname();
  40.  
  41. /* The following are to be used in assignment context, not in comparisons. */
  42.  
  43. #define    GOOD    1
  44. #define    BAD    0
  45.  
  46.  /*
  47.   * The apollo sr10.3 getpeername(2) does not return an error in case of a
  48.   * datagram-oriented socket. Instead, it claims that all UDP or RPC requests
  49.   * come from address 0.0.0.0. The following code works around the problem.
  50.   */
  51.  
  52. #ifdef GETPEERNAME_BUG
  53.  
  54. static int fix_getpeername(sock, sa, len)
  55. int     sock;
  56. struct sockaddr *sa;
  57. int    *len;
  58. {
  59.     int     ret;
  60.     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
  61.  
  62.     if ((ret = getpeername(sock, sa, len)) >= 0
  63.     && sa->sa_family == AF_INET
  64.     && strcmp(inet_ntoa(sin->sin_addr), "0.0.0.0") == 0) {
  65.     errno = ENOTCONN;
  66.     return (-1);
  67.     } else {
  68.     return (ret);
  69.     }
  70. }
  71.  
  72. #define    getpeername    fix_getpeername
  73. #endif
  74.  
  75. /* fromhost - find out what is at the other end of standard input */
  76.  
  77. int     fromhost(f)
  78. struct from_host *f;
  79. {
  80.     struct sockaddr sa;
  81.     struct sockaddr_in *sin = (struct sockaddr_in *) (&sa);
  82.     struct hostent *hp;
  83.     int     length = sizeof(sa);
  84.     char    buf[BUFSIZ];
  85.  
  86.     /*
  87.      * Look up the remote host address. Hal R. Brand <BRAND@addvax.llnl.gov>
  88.      * suggested how to get the remote host info in case of UDP connections:
  89.      * peek at the first message without actually looking at its contents.
  90.      */
  91.  
  92. #define    punt(name) { f->sock_type = 0; strcpy(f->source, name); return(0); }
  93.  
  94.     if (getpeername(0, &sa, &length) >= 0) {    /* assume TCP request */
  95.     f->sock_type = FROM_CONNECTED;
  96.     } else {
  97.     switch (errno) {
  98.     case ENOTSOCK:                /* stdin is not a socket */
  99.         punt(isatty(0) ? "stdin" : "unknown");
  100.     case ENOTCONN:                /* assume UDP request */
  101.         if (recvfrom(0, buf, sizeof(buf), MSG_PEEK, &sa, &length) < 0) {
  102.         syslog(LOG_ERR, "recvfrom: %m");
  103.         punt("unknown");
  104.         }
  105.         f->sock_type = FROM_UNCONNECTED;
  106.         break;
  107.     default:                /* other, punt */
  108.         syslog(LOG_ERR, "getpeername: %m");
  109.         punt("unknown");
  110.     }
  111.     }
  112.  
  113.     /*
  114.      * Now that we have the remote host address, look up the remote host
  115.      * name. Use the address if name lookup fails. At present, we can only
  116.      * handle names or addresses that belong to the AF_INET addres family.
  117.      */
  118.  
  119.     if (sa.sa_family != AF_INET) {
  120.     syslog(LOG_ERR, "unexpected address family %ld", (long) sa.sa_family);
  121.     strcpy(f->source, "unknown");
  122.     return (0);
  123.     }
  124.     if ((hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
  125.                 sizeof(sin->sin_addr.s_addr),
  126.                 AF_INET)) == 0) {
  127.     strcpy(f->source, inet_ntoa(sin->sin_addr));    /* use address */
  128.     return (0);
  129.     }
  130.  
  131.     /*
  132.      * Save the host name, even if we may decide to not use it, because the
  133.      * next gethostbyxxx() call will clobber it.
  134.      */
  135.  
  136.     strncpy(f->source, hp->h_name, sizeof(f->source) - 1);
  137.     f->source[sizeof(f->source) - 1] = 0;
  138.  
  139.     /*
  140.      * Verify that the host name does not belong to someone else. If host
  141.      * name verification fails, ignore the host name and use the address
  142.      * instead.
  143.      */
  144.  
  145.     if (matchname(f->source, sin)) {
  146.     return (0);
  147.     } else {
  148.     strcpy(f->source, inet_ntoa(sin->sin_addr));
  149.     return (-1);                /* verification failed */
  150.     }
  151. }
  152.  
  153. /* matchname - determine if host name matches IP address */
  154.  
  155. static int matchname(remotehost, sin)
  156. char   *remotehost;
  157. struct sockaddr_in *sin;
  158. {
  159.     struct hostent *hp;
  160.     int     i;
  161.  
  162.     if ((hp = gethostbyname(remotehost)) == 0) {
  163.  
  164.     /*
  165.      * Unable to verify that the host name matches the address. This may
  166.      * be a transient problem or a botched name server setup. We decide
  167.      * to play safe.
  168.      */
  169.  
  170.     syslog(LOG_ERR, "gethostbyname(%s): lookup failure", remotehost);
  171.     return (BAD);
  172.  
  173.     } else {
  174.  
  175.     /* Look up the host address in the address list we just got. */
  176.  
  177.     for (i = 0; hp->h_addr_list[i]; i++) {
  178.         if (memcmp(hp->h_addr_list[i],
  179.                (caddr_t) & sin->sin_addr,
  180.                sizeof(sin->sin_addr)) == 0)
  181.         return (GOOD);
  182.     }
  183.  
  184.     /*
  185.      * The host name does not map to the original host address. Perhaps
  186.      * someone has compromised a name server. More likely someone botched
  187.      * it, but that could be dangerous, too.
  188.      */
  189.  
  190.     syslog(LOG_ERR, "host name/address mismatch: %s != %s",
  191.            inet_ntoa(sin->sin_addr), hp->h_name);
  192.     return (BAD);
  193.     }
  194. }
  195.  
  196. #ifdef TEST
  197.  
  198. /* Code for stand-alone testing. */
  199.  
  200. main(argc, argv)
  201. int     argc;
  202. char  **argv;
  203. {
  204.     struct from_host from;
  205.  
  206. #ifdef LOG_MAIL
  207.     (void) openlog(argv[0], LOG_PID, FACILITY);
  208. #else
  209.     (void) openlog(argv[0], LOG_PID);
  210. #endif
  211.     (void) fromhost(&from);
  212.     printf("%s\n", from.source);
  213.     return (0);
  214. }
  215.  
  216. #endif
  217.