106c1483markm /*
206c1483markm  * This module determines the type of socket (datagram, stream), the client
306c1483markm  * socket address and port, the server socket address and port. In addition,
406c1483markm  * it provides methods to map a transport address to a printable host name
506c1483markm  * or address. Socket address information results are in static memory.
606c1483markm  *
706c1483markm  * The result from the hostname lookup method is STRING_PARANOID when a host
806c1483markm  * pretends to have someone elses name, or when a host name is available but
906c1483markm  * could not be verified.
1006c1483markm  *
1106c1483markm  * When lookup or conversion fails the result is set to STRING_UNKNOWN.
1206c1483markm  *
1306c1483markm  * Diagnostics are reported through syslog(3).
1406c1483markm  *
1506c1483markm  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
16225d233shin  *
17225d233shin  * $FreeBSD$
1806c1483markm  */
1906c1483markm
2006c1483markm#ifndef lint
2106c1483markmstatic char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24";
2206c1483markm#endif
2306c1483markm
2406c1483markm/* System libraries. */
2506c1483markm
2606c1483markm#include <sys/types.h>
2706c1483markm#include <sys/param.h>
2806c1483markm#include <sys/socket.h>
2906c1483markm#include <netinet/in.h>
3006c1483markm#include <netdb.h>
3106c1483markm#include <stdio.h>
3206c1483markm#include <syslog.h>
3306c1483markm#include <string.h>
3406c1483markm
35e33ba03ume#ifndef INET6
3606c1483markmextern char *inet_ntoa();
3770f27cdume#endif
3806c1483markm
3906c1483markm/* Local stuff. */
4006c1483markm
4106c1483markm#include "tcpd.h"
4206c1483markm
4306c1483markm/* Forward declarations. */
4406c1483markm
4558d8ce3brooksstatic void sock_sink(int);
4606c1483markm
4706c1483markm#ifdef APPEND_DOT
4806c1483markm
4906c1483markm /*
5006c1483markm  * Speed up DNS lookups by terminating the host name with a dot. Should be
5106c1483markm  * done with care. The speedup can give problems with lookups from sources
5206c1483markm  * that lack DNS-style trailing dot magic, such as local files or NIS maps.
5306c1483markm  */
5406c1483markm
5506c1483markmstatic struct hostent *gethostbyname_dot(name)
5606c1483markmchar   *name;
5706c1483markm{
5806c1483markm    char    dot_name[MAXHOSTNAMELEN + 1];
5906c1483markm
6006c1483markm    /*
6106c1483markm     * Don't append dots to unqualified names. Such names are likely to come
6206c1483markm     * from local hosts files or from NIS.
6306c1483markm     */
6406c1483markm
6506c1483markm    if (strchr(name, '.') == 0 || strlen(name) >= MAXHOSTNAMELEN - 1) {
6606c1483markm	return (gethostbyname(name));
6706c1483markm    } else {
6806c1483markm	sprintf(dot_name, "%s.", name);
6906c1483markm	return (gethostbyname(dot_name));
7006c1483markm    }
7106c1483markm}
7206c1483markm
7306c1483markm#define gethostbyname gethostbyname_dot
7406c1483markm#endif
7506c1483markm
7606c1483markm/* sock_host - look up endpoint addresses and install conversion methods */
7706c1483markm
7806c1483markmvoid    sock_host(request)
7906c1483markmstruct request_info *request;
8006c1483markm{
81225d233shin#ifdef INET6
82225d233shin    static struct sockaddr_storage client;
83225d233shin    static struct sockaddr_storage server;
84225d233shin#else
8506c1483markm    static struct sockaddr_in client;
8606c1483markm    static struct sockaddr_in server;
87225d233shin#endif
8806c1483markm    int     len;
8906c1483markm    char    buf[BUFSIZ];
9006c1483markm    int     fd = request->fd;
9106c1483markm
9206c1483markm    sock_methods(request);
9306c1483markm
9406c1483markm    /*
9506c1483markm     * Look up the client host address. Hal R. Brand <BRAND@addvax.llnl.gov>
9606c1483markm     * suggested how to get the client host info in case of UDP connections:
9706c1483markm     * peek at the first message without actually looking at its contents. We
9806c1483markm     * really should verify that client.sin_family gets the value AF_INET,
9906c1483markm     * but this program has already caused too much grief on systems with
10006c1483markm     * broken library code.
10106c1483markm     */
10206c1483markm
10306c1483markm    len = sizeof(client);
10406c1483markm    if (getpeername(fd, (struct sockaddr *) & client, &len) < 0) {
10506c1483markm	request->sink = sock_sink;
10606c1483markm	len = sizeof(client);
10706c1483markm	if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK,
10806c1483markm		     (struct sockaddr *) & client, &len) < 0) {
10906c1483markm	    tcpd_warn("can't get client address: %m");
11006c1483markm	    return;				/* give up */
11106c1483markm	}
11206c1483markm#ifdef really_paranoid
1138470721ceri	memset(buf, 0, sizeof(buf));
11406c1483markm#endif
11506c1483markm    }
116225d233shin#ifdef INET6
117225d233shin    request->client->sin = (struct sockaddr *)&client;
118225d233shin#else
11906c1483markm    request->client->sin = &client;
120225d233shin#endif
12106c1483markm
12206c1483markm    /*
12306c1483markm     * Determine the server binding. This is used for client username
12406c1483markm     * lookups, and for access control rules that trigger on the server
12506c1483markm     * address or name.
12606c1483markm     */
12706c1483markm
12806c1483markm    len = sizeof(server);
12906c1483markm    if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) {
13006c1483markm	tcpd_warn("getsockname: %m");
13106c1483markm	return;
13206c1483markm    }
133225d233shin#ifdef INET6
134225d233shin    request->server->sin = (struct sockaddr *)&server;
135225d233shin#else
13606c1483markm    request->server->sin = &server;
137225d233shin#endif
13806c1483markm}
13906c1483markm
14006c1483markm/* sock_hostaddr - map endpoint address to printable form */
14106c1483markm
14206c1483markmvoid    sock_hostaddr(host)
14306c1483markmstruct host_info *host;
14406c1483markm{
145225d233shin#ifdef INET6
146225d233shin    struct sockaddr *sin = host->sin;
14770f27cdume    int salen;
148225d233shin
149225d233shin    if (!sin)
150225d233shin	return;
15170f27cdume#ifdef SIN6_LEN
15270f27cdume    salen = sin->sa_len;
15370f27cdume#else
15470f27cdume    salen = (sin->sa_family == AF_INET) ? sizeof(struct sockaddr_in)
15570f27cdume					: sizeof(struct sockaddr_in6);
15670f27cdume#endif
15770f27cdume    getnameinfo(sin, salen, host->addr, sizeof(host->addr),
158e33ba03ume		NULL, 0, NI_NUMERICHOST);
159225d233shin#else
16006c1483markm    struct sockaddr_in *sin = host->sin;
16106c1483markm
16206c1483markm    if (sin != 0)
16306c1483markm	STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr));
164225d233shin#endif
16506c1483markm}
16606c1483markm
16706c1483markm/* sock_hostname - map endpoint address to host name */
16806c1483markm
16906c1483markmvoid    sock_hostname(host)
17006c1483markmstruct host_info *host;
17106c1483markm{
172225d233shin#ifdef INET6
173225d233shin    struct sockaddr *sin = host->sin;
17470f27cdume    struct sockaddr_in sin4;
17570f27cdume    struct addrinfo hints, *res, *res0 = NULL;
17670f27cdume    int salen, alen, err = 1;
17770f27cdume    char *ap = NULL, *rap, hname[NI_MAXHOST];
17870f27cdume
17970f27cdume    if (sin != NULL) {
18070f27cdume	if (sin->sa_family == AF_INET6) {
18170f27cdume	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sin;
18270f27cdume
18370f27cdume	    if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
18470f27cdume		memset(&sin4, 0, sizeof(sin4));
18570f27cdume#ifdef SIN6_LEN
18670f27cdume		sin4.sin_len = sizeof(sin4);
187225d233shin#endif
18870f27cdume		sin4.sin_family = AF_INET;
18970f27cdume		sin4.sin_port = sin6->sin6_port;
19070f27cdume		sin4.sin_addr.s_addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
19170f27cdume		sin = (struct sockaddr *)&sin4;
19270f27cdume	    }
19370f27cdume	}
19470f27cdume	switch (sin->sa_family) {
19570f27cdume	case AF_INET:
19670f27cdume	    ap = (char *)&((struct sockaddr_in *)sin)->sin_addr;
19770f27cdume	    alen = sizeof(struct in_addr);
19870f27cdume	    salen = sizeof(struct sockaddr_in);
19970f27cdume	    break;
20070f27cdume	case AF_INET6:
20170f27cdume	    ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr;
20270f27cdume	    alen = sizeof(struct in6_addr);
20370f27cdume	    salen = sizeof(struct sockaddr_in6);
20470f27cdume	    break;
20570f27cdume	default:
20670f27cdume	    break;
20770f27cdume	}
20870f27cdume	if (ap)
20970f27cdume	    err = getnameinfo(sin, salen, hname, sizeof(hname),
210e33ba03ume			      NULL, 0, NI_NAMEREQD);
21170f27cdume    }
21270f27cdume    if (!err) {
21370f27cdume
21470f27cdume	STRN_CPY(host->name, hname, sizeof(host->name));
21570f27cdume
2166070b58ume	/* reject numeric addresses */
2176070b58ume	memset(&hints, 0, sizeof(hints));
2186070b58ume	hints.ai_family = sin->sa_family;
2196070b58ume	hints.ai_socktype = SOCK_STREAM;
2206070b58ume	hints.ai_flags = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST;
22176f9847kris	if ((err = getaddrinfo(host->name, NULL, &hints, &res0)) == 0) {
2226070b58ume	    freeaddrinfo(res0);
2236070b58ume	    tcpd_warn("host name/name mismatch: "
2246070b58ume		      "reverse lookup results in non-FQDN %s",
2256070b58ume		      host->name);
2266070b58ume	    strcpy(host->name, paranoid);	/* name is bad, clobber it */
2276070b58ume	}
2286070b58ume	err = !err;
2296070b58ume    }
2306070b58ume    if (!err) {
2316070b58ume	/* we are now sure that this is non-numeric */
2326070b58ume
23370f27cdume	/*
23470f27cdume	 * Verify that the address is a member of the address list returned
23570f27cdume	 * by gethostbyname(hostname).
23670f27cdume	 *
23770f27cdume	 * Verify also that gethostbyaddr() and gethostbyname() return the same
23870f27cdume	 * hostname, or rshd and rlogind may still end up being spoofed.
23970f27cdume	 *
24070f27cdume	 * On some sites, gethostbyname("localhost") returns "localhost.domain".
24170f27cdume	 * This is a DNS artefact. We treat it as a special case. When we
24270f27cdume	 * can't believe the address list from gethostbyname("localhost")
24370f27cdume	 * we're in big trouble anyway.
24470f27cdume	 */
24570f27cdume
24670f27cdume	memset(&hints, 0, sizeof(hints));
24770f27cdume	hints.ai_family = sin->sa_family;
24870f27cdume	hints.ai_socktype = SOCK_STREAM;
24970f27cdume	hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
25070f27cdume	if (getaddrinfo(host->name, NULL, &hints, &res0) != 0) {
25170f27cdume
25270f27cdume	    /*
25370f27cdume	     * Unable to verify that the host name matches the address. This
25470f27cdume	     * may be a transient problem or a botched name server setup.
25570f27cdume	     */
25670f27cdume
25770f27cdume	    tcpd_warn("can't verify hostname: getaddrinfo(%s, %s) failed",
25870f27cdume		      host->name,
25970f27cdume		      (sin->sa_family == AF_INET) ? "AF_INET" : "AF_INET6");
26070f27cdume
2617478417ume	} else if ((res0->ai_canonname == NULL
2627478417ume		    || STR_NE(host->name, res0->ai_canonname))
26370f27cdume		   && STR_NE(host->name, "localhost")) {
26470f27cdume
26570f27cdume	    /*
26670f27cdume	     * The gethostbyaddr() and gethostbyname() calls did not return
26770f27cdume	     * the same hostname. This could be a nameserver configuration
26870f27cdume	     * problem. It could also be that someone is trying to spoof us.
26970f27cdume	     */
27070f27cdume
27170f27cdume	    tcpd_warn("host name/name mismatch: %s != %.*s",
2727478417ume		      host->name, STRING_LENGTH,
2737478417ume		      (res0->ai_canonname == NULL) ? "" : res0->ai_canonname);
27470f27cdume
27570f27cdume	} else {
27670f27cdume
27770f27cdume	    /*
27870f27cdume	     * The address should be a member of the address list returned by
27970f27cdume	     * gethostbyname(). We should first verify that the h_addrtype
28070f27cdume	     * field is AF_INET, but this program has already caused too much
28170f27cdume	     * grief on systems with broken library code.
28270f27cdume	     */
28370f27cdume
28470f27cdume	    for (res = res0; res; res = res->ai_next) {
28570f27cdume		if (res->ai_family != sin->sa_family)
28670f27cdume		    continue;
28770f27cdume		switch (res->ai_family) {
28870f27cdume		case AF_INET:
28970f27cdume		    rap = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr;
29070f27cdume		    break;
29170f27cdume		case AF_INET6:
2926070b58ume		    /* need to check scope_id */
2936070b58ume		    if (((struct sockaddr_in6 *)sin)->sin6_scope_id !=
2946070b58ume		        ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id) {
2956070b58ume			continue;
2966070b58ume		    }
29770f27cdume		    rap = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
29870f27cdume		    break;
29970f27cdume		default:
30070f27cdume		    continue;
30170f27cdume		}
30270f27cdume		if (memcmp(rap, ap, alen) == 0) {
30370f27cdume		    freeaddrinfo(res0);
30470f27cdume		    return;			/* name is good, keep it */
30570f27cdume		}
30670f27cdume	    }
30770f27cdume
30870f27cdume	    /*
30970f27cdume	     * The host name does not map to the initial address. Perhaps
31070f27cdume	     * someone has messed up. Perhaps someone compromised a name
31170f27cdume	     * server.
31270f27cdume	     */
31370f27cdume
31470f27cdume	    getnameinfo(sin, salen, hname, sizeof(hname),
315e33ba03ume			NULL, 0, NI_NUMERICHOST);
31670f27cdume	    tcpd_warn("host name/address mismatch: %s != %.*s",
3177478417ume		      hname, STRING_LENGTH,
3187478417ume		      (res0->ai_canonname == NULL) ? "" : res0->ai_canonname);
31970f27cdume	}
32070f27cdume	strcpy(host->name, paranoid);		/* name is bad, clobber it */
32170f27cdume	if (res0)
32270f27cdume	    freeaddrinfo(res0);
32370f27cdume    }
32470f27cdume#else /* INET6 */
32506c1483markm    struct sockaddr_in *sin = host->sin;
32606c1483markm    struct hostent *hp;
32706c1483markm    int     i;
32806c1483markm
32906c1483markm    /*
33006c1483markm     * On some systems, for example Solaris 2.3, gethostbyaddr(0.0.0.0) does
33106c1483markm     * not fail. Instead it returns "INADDR_ANY". Unfortunately, this does
33206c1483markm     * not work the other way around: gethostbyname("INADDR_ANY") fails. We
33306c1483markm     * have to special-case 0.0.0.0, in order to avoid false alerts from the
33406c1483markm     * host name/address checking code below.
33506c1483markm     */
33606c1483markm    if (sin != 0 && sin->sin_addr.s_addr != 0
33706c1483markm	&& (hp = gethostbyaddr((char *) &(sin->sin_addr),
33806c1483markm			       sizeof(sin->sin_addr), AF_INET)) != 0) {
33906c1483markm
34006c1483markm	STRN_CPY(host->name, hp->h_name, sizeof(host->name));
34106c1483markm
34206c1483markm	/*
34306c1483markm	 * Verify that the address is a member of the address list returned
34406c1483markm	 * by gethostbyname(hostname).
34506c1483markm	 *
34606c1483markm	 * Verify also that gethostbyaddr() and gethostbyname() return the same
34706c1483markm	 * hostname, or rshd and rlogind may still end up being spoofed.
34806c1483markm	 *
34906c1483markm	 * On some sites, gethostbyname("localhost") returns "localhost.domain".
35006c1483markm	 * This is a DNS artefact. We treat it as a special case. When we
35106c1483markm	 * can't believe the address list from gethostbyname("localhost")
35206c1483markm	 * we're in big trouble anyway.
35306c1483markm	 */
35406c1483markm
35506c1483markm	if ((hp = gethostbyname(host->name)) == 0) {
35606c1483markm
35706c1483markm	    /*
35806c1483markm	     * Unable to verify that the host name matches the address. This
35906c1483markm	     * may be a transient problem or a botched name server setup.
36006c1483markm	     */
36106c1483markm
36206c1483markm	    tcpd_warn("can't verify hostname: gethostbyname(%s) failed",
36306c1483markm		      host->name);
36406c1483markm
36506c1483markm	} else if (STR_NE(host->name, hp->h_name)
36606c1483markm		   && STR_NE(host->name, "localhost")) {
36706c1483markm
36806c1483markm	    /*
36906c1483markm	     * The gethostbyaddr() and gethostbyname() calls did not return
37006c1483markm	     * the same hostname. This could be a nameserver configuration
37106c1483markm	     * problem. It could also be that someone is trying to spoof us.
37206c1483markm	     */
37306c1483markm
37406c1483markm	    tcpd_warn("host name/name mismatch: %s != %.*s",
37506c1483markm		      host->name, STRING_LENGTH, hp->h_name);
37606c1483markm
37706c1483markm	} else {
37806c1483markm
37906c1483markm	    /*
38006c1483markm	     * The address should be a member of the address list returned by
38106c1483markm	     * gethostbyname(). We should first verify that the h_addrtype
38206c1483markm	     * field is AF_INET, but this program has already caused too much
38306c1483markm	     * grief on systems with broken library code.
38406c1483markm	     */
38506c1483markm
38606c1483markm	    for (i = 0; hp->h_addr_list[i]; i++) {
38706c1483markm		if (memcmp(hp->h_addr_list[i],
38806c1483markm			   (char *) &sin->sin_addr,
38906c1483markm			   sizeof(sin->sin_addr)) == 0)
39006c1483markm		    return;			/* name is good, keep it */
39106c1483markm	    }
39206c1483markm
39306c1483markm	    /*
39406c1483markm	     * The host name does not map to the initial address. Perhaps
39506c1483markm	     * someone has messed up. Perhaps someone compromised a name
39606c1483markm	     * server.
39706c1483markm	     */
39806c1483markm
39906c1483markm	    tcpd_warn("host name/address mismatch: %s != %.*s",
40006c1483markm		      inet_ntoa(sin->sin_addr), STRING_LENGTH, hp->h_name);
40106c1483markm	}
40206c1483markm	strcpy(host->name, paranoid);		/* name is bad, clobber it */
40306c1483markm    }
40470f27cdume#endif /* INET6 */
40506c1483markm}
40606c1483markm
40706c1483markm/* sock_sink - absorb unreceived IP datagram */
40806c1483markm
40958d8ce3brooksstatic void sock_sink(int fd)
41006c1483markm{
41106c1483markm    char    buf[BUFSIZ];
412225d233shin#ifdef INET6
413225d233shin    struct sockaddr_storage sin;
414225d233shin#else
41506c1483markm    struct sockaddr_in sin;
416225d233shin#endif
41706c1483markm    int     size = sizeof(sin);
41806c1483markm
41906c1483markm    /*
42006c1483markm     * Eat up the not-yet received datagram. Some systems insist on a
42106c1483markm     * non-zero source address argument in the recvfrom() call below.
42206c1483markm     */
42306c1483markm
42406c1483markm    (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sin, &size);
42506c1483markm}
426