Home | History | Annotate | Line # | Download | only in libwrap
socket.c revision 1.7
      1 /*	$NetBSD: socket.c,v 1.7 1999/08/31 13:58:58 itojun Exp $	*/
      2 
      3  /*
      4   * This module determines the type of socket (datagram, stream), the client
      5   * socket address and port, the server socket address and port. In addition,
      6   * it provides methods to map a transport address to a printable host name
      7   * or address. Socket address information results are in static memory.
      8   *
      9   * The result from the hostname lookup method is STRING_PARANOID when a host
     10   * pretends to have someone elses name, or when a host name is available but
     11   * could not be verified.
     12   *
     13   * When lookup or conversion fails the result is set to STRING_UNKNOWN.
     14   *
     15   * Diagnostics are reported through syslog(3).
     16   *
     17   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
     18   */
     19 
     20 #include <sys/cdefs.h>
     21 #ifndef lint
     22 #if 0
     23 static char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24";
     24 #else
     25 __RCSID("$NetBSD: socket.c,v 1.7 1999/08/31 13:58:58 itojun Exp $");
     26 #endif
     27 #endif
     28 
     29 /* System libraries. */
     30 
     31 #include <sys/types.h>
     32 #include <sys/param.h>
     33 #include <sys/socket.h>
     34 #include <netinet/in.h>
     35 #include <netdb.h>
     36 #include <stdio.h>
     37 #include <syslog.h>
     38 #include <string.h>
     39 #include <arpa/inet.h>
     40 
     41 /* Local stuff. */
     42 
     43 #include "tcpd.h"
     44 
     45 /* Forward declarations. */
     46 
     47 static void sock_sink __P((int));
     48 
     49 #ifdef APPEND_DOT
     50 static struct hostent *gethostbyname_dot __P((char *));
     51 
     52  /*
     53   * Speed up DNS lookups by terminating the host name with a dot. Should be
     54   * done with care. The speedup can give problems with lookups from sources
     55   * that lack DNS-style trailing dot magic, such as local files or NIS maps.
     56   */
     57 
     58 static struct hostent *gethostbyname_dot(name)
     59 char   *name;
     60 {
     61     char    dot_name[MAXHOSTNAMELEN + 1];
     62 
     63     /*
     64      * Don't append dots to unqualified names. Such names are likely to come
     65      * from local hosts files or from NIS.
     66      */
     67 
     68     if (strchr(name, '.') == 0 || strlen(name) >= MAXHOSTNAMELEN - 1) {
     69 	return (gethostbyname(name));
     70     } else {
     71 	(void)snprintf(dot_name, sizeof dot_name, "%s.", name);
     72 	return (gethostbyname(dot_name));
     73     }
     74 }
     75 
     76 #define gethostbyname gethostbyname_dot
     77 #endif
     78 
     79 /* sock_host - look up endpoint addresses and install conversion methods */
     80 
     81 void    sock_host(request)
     82 struct request_info *request;
     83 {
     84     static struct sockaddr_storage client;
     85     static struct sockaddr_storage server;
     86     int     len;
     87     char    buf[BUFSIZ];
     88     int     fd = request->fd;
     89 
     90     sock_methods(request);
     91 
     92     /*
     93      * Look up the client host address. Hal R. Brand <BRAND (at) addvax.llnl.gov>
     94      * suggested how to get the client host info in case of UDP connections:
     95      * peek at the first message without actually looking at its contents. We
     96      * really should verify that client.sin_family gets the value AF_INET,
     97      * but this program has already caused too much grief on systems with
     98      * broken library code.
     99      *
    100      * XXX the last sentence is untrue as we support AF_INET6 as well :-)
    101      */
    102 
    103     len = sizeof(client);
    104     if (getpeername(fd, (struct sockaddr *) & client, &len) < 0) {
    105 	request->sink = sock_sink;
    106 	len = sizeof(client);
    107 	if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK,
    108 		     (struct sockaddr *) & client, &len) < 0) {
    109 	    tcpd_warn("can't get client address: %m");
    110 	    return;				/* give up */
    111 	}
    112 #ifdef really_paranoid
    113 	memset(buf, 0 sizeof(buf));
    114 #endif
    115     }
    116     request->client->sin = (struct sockaddr *)&client;
    117 
    118     /*
    119      * Determine the server binding. This is used for client username
    120      * lookups, and for access control rules that trigger on the server
    121      * address or name.
    122      */
    123 
    124     len = sizeof(server);
    125     if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) {
    126 	tcpd_warn("getsockname: %m");
    127 	return;
    128     }
    129     request->server->sin = (struct sockaddr *)&server;
    130 }
    131 
    132 /* sock_hostaddr - map endpoint address to printable form */
    133 
    134 void    sock_hostaddr(host)
    135 struct host_info *host;
    136 {
    137     struct sockaddr *sa = host->sin;
    138     int alen, af;
    139     char *ap;
    140 
    141     if (!sa)
    142 	return;
    143     switch (sa->sa_family) {
    144     case AF_INET:
    145 	ap = (char *)&((struct sockaddr_in *)sa)->sin_addr;
    146 	alen = sizeof(struct in_addr);
    147 	break;
    148 #ifdef INET6
    149     case AF_INET6:
    150 	ap = (char *)&((struct sockaddr_in6 *)sa)->sin6_addr;
    151 	alen = sizeof(struct in6_addr);
    152 	break;
    153 #endif
    154     default:
    155 	return;
    156     }
    157     host->addr[0] = '\0';
    158     inet_ntop(af, ap, host->addr, sizeof(host->addr));
    159 }
    160 
    161 /* sock_hostname - map endpoint address to host name */
    162 
    163 void    sock_hostname(host)
    164 struct host_info *host;
    165 {
    166     struct sockaddr *sin = host->sin;
    167     struct hostent *hp;
    168     int     i;
    169     int af, alen;
    170     char *ap;
    171     char hbuf[MAXHOSTNAMELEN];
    172 
    173     /*
    174      * On some systems, for example Solaris 2.3, gethostbyaddr(0.0.0.0) does
    175      * not fail. Instead it returns "INADDR_ANY". Unfortunately, this does
    176      * not work the other way around: gethostbyname("INADDR_ANY") fails. We
    177      * have to special-case 0.0.0.0, in order to avoid false alerts from the
    178      * host name/address checking code below.
    179      */
    180     if (!sin)
    181 	return;
    182     switch (af = sin->sa_family) {
    183     case AF_INET:
    184 	if (((struct sockaddr_in *)sin)->sin_addr.s_addr == 0)
    185 	    return;
    186 	ap = (char *)&((struct sockaddr_in *)sin)->sin_addr;
    187 	alen = sizeof(struct in_addr);
    188 	break;
    189 #ifdef INET6
    190     case AF_INET6:
    191 	ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr;
    192 	alen = sizeof(struct in6_addr);
    193 	/* special case on reverse lookup: mapped addr.  I hate it */
    194 	if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
    195 	    af = AF_INET;
    196 	    ap += (sizeof(struct in6_addr) - sizeof(struct in_addr));
    197 	    alen = sizeof(struct in_addr);
    198 	}
    199 	break;
    200 #endif
    201     default:
    202 	return;
    203     }
    204     if ((hp = gethostbyaddr(ap, alen, af)) != 0) {
    205 
    206 	STRN_CPY(host->name, hp->h_name, sizeof(host->name));
    207 
    208 	/*
    209 	 * Verify that the address is a member of the address list returned
    210 	 * by gethostbyname(hostname).
    211 	 *
    212 	 * Verify also that gethostbyaddr() and gethostbyname() return the same
    213 	 * hostname, or rshd and rlogind may still end up being spoofed.
    214 	 *
    215 	 * On some sites, gethostbyname("localhost") returns "localhost.domain".
    216 	 * This is a DNS artefact. We treat it as a special case. When we
    217 	 * can't believe the address list from gethostbyname("localhost")
    218 	 * we're in big trouble anyway.
    219 	 */
    220 
    221 	if ((hp = gethostbyname2(host->name, af)) == 0) {
    222 
    223 	    /*
    224 	     * Unable to verify that the host name matches the address. This
    225 	     * may be a transient problem or a botched name server setup.
    226 	     */
    227 
    228 	    tcpd_warn("can't verify hostname: gethostbyname2(%s, %d) failed",
    229 		      host->name, af);
    230 
    231 	} else if (STR_NE(host->name, hp->h_name)
    232 		   && STR_NE(host->name, "localhost")) {
    233 
    234 	    /*
    235 	     * The gethostbyaddr() and gethostbyname() calls did not return
    236 	     * the same hostname. This could be a nameserver configuration
    237 	     * problem. It could also be that someone is trying to spoof us.
    238 	     */
    239 
    240 	    tcpd_warn("host name/name mismatch: %s != %.*s",
    241 		      host->name, STRING_LENGTH, hp->h_name);
    242 
    243 	} else {
    244 
    245 	    /*
    246 	     * The address should be a member of the address list returned by
    247 	     * gethostbyname(). We should first verify that the h_addrtype
    248 	     * field is AF_INET, but this program has already caused too much
    249 	     * grief on systems with broken library code.
    250 	     */
    251 
    252 	    for (i = 0; hp->h_addr_list[i]; i++) {
    253 		if (memcmp(hp->h_addr_list[i], (char *) ap, alen) == 0)
    254 		    return;			/* name is good, keep it */
    255 	    }
    256 
    257 	    /*
    258 	     * The host name does not map to the initial address. Perhaps
    259 	     * someone has messed up. Perhaps someone compromised a name
    260 	     * server.
    261 	     */
    262 
    263 	    tcpd_warn("host name/address mismatch: %s != %.*s",
    264 		      inet_ntop(af, ap, hbuf, sizeof(hbuf)),
    265 		      STRING_LENGTH, hp->h_name);
    266 	}
    267 	/* name is bad, clobber it */
    268 	(void)strncpy(host->name, paranoid, sizeof(host->name) - 1);
    269     }
    270 }
    271 
    272 /* sock_sink - absorb unreceived IP datagram */
    273 
    274 static void sock_sink(fd)
    275 int     fd;
    276 {
    277     char    buf[BUFSIZ];
    278     struct sockaddr_storage sin;
    279     int     size = sizeof(sin);
    280 
    281     /*
    282      * Eat up the not-yet received datagram. Some systems insist on a
    283      * non-zero source address argument in the recvfrom() call below.
    284      */
    285 
    286     (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sin, &size);
    287 }
    288