1*e1a2f47fSmatt /* $NetBSD: socket.c,v 1.19 2012/03/21 10:10:37 matt Exp $ */
2d6ddaab4Schristos
3541be36cSmrg /*
4541be36cSmrg * This module determines the type of socket (datagram, stream), the client
5541be36cSmrg * socket address and port, the server socket address and port. In addition,
6541be36cSmrg * it provides methods to map a transport address to a printable host name
7541be36cSmrg * or address. Socket address information results are in static memory.
8541be36cSmrg *
9541be36cSmrg * The result from the hostname lookup method is STRING_PARANOID when a host
10541be36cSmrg * pretends to have someone elses name, or when a host name is available but
11541be36cSmrg * could not be verified.
12541be36cSmrg *
13541be36cSmrg * When lookup or conversion fails the result is set to STRING_UNKNOWN.
14541be36cSmrg *
15541be36cSmrg * Diagnostics are reported through syslog(3).
16541be36cSmrg *
17541be36cSmrg * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
18541be36cSmrg */
19541be36cSmrg
20d6ddaab4Schristos #include <sys/cdefs.h>
21541be36cSmrg #ifndef lint
22d6ddaab4Schristos #if 0
23b98c2633Sitojun static char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24";
24d6ddaab4Schristos #else
25*e1a2f47fSmatt __RCSID("$NetBSD: socket.c,v 1.19 2012/03/21 10:10:37 matt Exp $");
26d6ddaab4Schristos #endif
27541be36cSmrg #endif
28541be36cSmrg
29541be36cSmrg /* System libraries. */
30541be36cSmrg
31541be36cSmrg #include <sys/types.h>
32541be36cSmrg #include <sys/param.h>
33541be36cSmrg #include <sys/socket.h>
34541be36cSmrg #include <netinet/in.h>
35541be36cSmrg #include <netdb.h>
36541be36cSmrg #include <stdio.h>
37541be36cSmrg #include <syslog.h>
38541be36cSmrg #include <string.h>
39d6ddaab4Schristos #include <arpa/inet.h>
40541be36cSmrg
41541be36cSmrg /* Local stuff. */
42541be36cSmrg
43541be36cSmrg #include "tcpd.h"
44541be36cSmrg
45541be36cSmrg /* Forward declarations. */
46541be36cSmrg
4744772e4bSitojun #ifdef APPEND_DOT
4844772e4bSitojun static const char *append_dot __P((const char *));
4944772e4bSitojun #endif
50d6ddaab4Schristos static void sock_sink __P((int));
51541be36cSmrg
5244772e4bSitojun #ifdef APPEND_DOT
5344772e4bSitojun /*
5444772e4bSitojun * Speed up DNS lookups by terminating the host name with a dot. Should be
5544772e4bSitojun * done with care. The speedup can give problems with lookups from sources
5644772e4bSitojun * that lack DNS-style trailing dot magic, such as local files or NIS maps.
5744772e4bSitojun */
5844772e4bSitojun
5944772e4bSitojun static const char *
append_dot(name)6044772e4bSitojun append_dot(name)
61d2503f64Sitojun const char *name;
6244772e4bSitojun {
6344772e4bSitojun static char hbuf[MAXHOSTNAMELEN + 1];
6444772e4bSitojun
6544772e4bSitojun /*
6644772e4bSitojun * Don't append dots to unqualified names. Such names are likely to come
6744772e4bSitojun * from local hosts files or from NIS.
6844772e4bSitojun */
6944772e4bSitojun
7044772e4bSitojun if (strchr(name, '.') == 0 || strlen(name) + 2 > sizeof(hbuf))
7144772e4bSitojun strlcpy(hbuf, name, sizeof(hbuf));
7244772e4bSitojun else
7344772e4bSitojun (void)snprintf(hbuf, sizeof(hbuf), "%s.", name);
7444772e4bSitojun return hbuf;
7544772e4bSitojun }
7644772e4bSitojun #endif
7744772e4bSitojun
78541be36cSmrg /* sock_host - look up endpoint addresses and install conversion methods */
79541be36cSmrg
80*e1a2f47fSmatt void
sock_host(struct request_info * request)81*e1a2f47fSmatt sock_host(struct request_info *request)
82541be36cSmrg {
831e8c736aSitojun static struct sockaddr_storage client;
841e8c736aSitojun static struct sockaddr_storage server;
850c37c63eSmrg socklen_t len;
86541be36cSmrg char buf[BUFSIZ];
87541be36cSmrg int fd = request->fd;
88541be36cSmrg
89541be36cSmrg sock_methods(request);
90541be36cSmrg
91541be36cSmrg /*
92541be36cSmrg * Look up the client host address. Hal R. Brand <BRAND@addvax.llnl.gov>
93541be36cSmrg * suggested how to get the client host info in case of UDP connections:
94541be36cSmrg * peek at the first message without actually looking at its contents. We
95541be36cSmrg * really should verify that client.sin_family gets the value AF_INET,
96541be36cSmrg * but this program has already caused too much grief on systems with
97541be36cSmrg * broken library code.
981e8c736aSitojun *
991e8c736aSitojun * XXX the last sentence is untrue as we support AF_INET6 as well :-)
100541be36cSmrg */
101541be36cSmrg
10240e1466eSthorpej if (request->client->sin == NULL) {
103541be36cSmrg len = sizeof(client);
1040c37c63eSmrg if (getpeername(fd, (struct sockaddr *)(void *)& client, &len) < 0) {
105541be36cSmrg request->sink = sock_sink;
106541be36cSmrg len = sizeof(client);
107541be36cSmrg if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK,
108541be36cSmrg (struct sockaddr *) & client, &len) < 0) {
109541be36cSmrg tcpd_warn("can't get client address: %m");
110541be36cSmrg return; /* give up */
111541be36cSmrg }
112541be36cSmrg #ifdef really_paranoid
113c4557301Smjl memset(buf, 0, sizeof(buf));
114541be36cSmrg #endif
115541be36cSmrg }
1161e8c736aSitojun request->client->sin = (struct sockaddr *)&client;
11740e1466eSthorpej }
118541be36cSmrg
119541be36cSmrg /*
120541be36cSmrg * Determine the server binding. This is used for client username
121541be36cSmrg * lookups, and for access control rules that trigger on the server
122541be36cSmrg * address or name.
123541be36cSmrg */
124541be36cSmrg
12540e1466eSthorpej if (request->server->sin == NULL) {
126541be36cSmrg len = sizeof(server);
127541be36cSmrg if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) {
128541be36cSmrg tcpd_warn("getsockname: %m");
129541be36cSmrg return;
130541be36cSmrg }
1311e8c736aSitojun request->server->sin = (struct sockaddr *)&server;
132541be36cSmrg }
13340e1466eSthorpej }
134541be36cSmrg
135541be36cSmrg /* sock_hostaddr - map endpoint address to printable form */
136541be36cSmrg
137*e1a2f47fSmatt void
sock_hostaddr(struct host_info * host)138*e1a2f47fSmatt sock_hostaddr(struct host_info *host)
139541be36cSmrg {
1401e8c736aSitojun struct sockaddr *sa = host->sin;
141541be36cSmrg
1421e8c736aSitojun if (!sa)
1431e8c736aSitojun return;
1441e8c736aSitojun host->addr[0] = '\0';
1452f7d82e6Sitojun getnameinfo(sa, sa->sa_len, host->addr, sizeof(host->addr),
1462f7d82e6Sitojun NULL, 0, NI_NUMERICHOST);
147541be36cSmrg }
148541be36cSmrg
149541be36cSmrg /* sock_hostname - map endpoint address to host name */
150541be36cSmrg
151*e1a2f47fSmatt void
sock_hostname(struct host_info * host)152*e1a2f47fSmatt sock_hostname(struct host_info *host)
153541be36cSmrg {
1542f7d82e6Sitojun struct sockaddr *sa = host->sin;
1552f7d82e6Sitojun char h1[NI_MAXHOST], h2[NI_MAXHOST];
1562f7d82e6Sitojun struct addrinfo hints, *res, *res0;
1571e8c736aSitojun #ifdef INET6
1582f7d82e6Sitojun struct sockaddr_in tmp;
1591e8c736aSitojun #endif
1602f7d82e6Sitojun
1612f7d82e6Sitojun if (!sa)
1622f7d82e6Sitojun return;
1632f7d82e6Sitojun #ifdef INET6
1642f7d82e6Sitojun /* special case on reverse lookup: mapped addr. I hate it */
1652f7d82e6Sitojun if (sa->sa_family == AF_INET6 &&
1662f7d82e6Sitojun IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) {
1672f7d82e6Sitojun memset(&tmp, 0, sizeof(tmp));
1682f7d82e6Sitojun tmp.sin_family = AF_INET;
1692f7d82e6Sitojun tmp.sin_len = sizeof(struct sockaddr_in);
1702f7d82e6Sitojun memcpy(&tmp.sin_addr,
1712f7d82e6Sitojun &((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[12], 4);
1722f7d82e6Sitojun sa = (struct sockaddr *)&tmp;
1732f7d82e6Sitojun }
1742f7d82e6Sitojun #endif
1752f7d82e6Sitojun if (getnameinfo(sa, sa->sa_len, h1, sizeof(h1), NULL, 0,
1762f7d82e6Sitojun NI_NUMERICHOST) != 0) {
1771e8c736aSitojun return;
1781e8c736aSitojun }
1792f7d82e6Sitojun if (getnameinfo(sa, sa->sa_len, host->name, sizeof(host->name), NULL, 0,
1802f7d82e6Sitojun NI_NAMEREQD) == 0) {
181541be36cSmrg /*
18274a87116Sitojun * if reverse lookup result looks like a numeric hostname,
18374a87116Sitojun * someone is trying to trick us by PTR record like following:
18474a87116Sitojun * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5
18574a87116Sitojun */
18674a87116Sitojun memset(&hints, 0, sizeof(hints));
18774a87116Sitojun hints.ai_socktype = SOCK_DGRAM; /*dummy*/
18874a87116Sitojun hints.ai_flags = AI_NUMERICHOST;
18974a87116Sitojun #ifdef APPEND_DOT
19074a87116Sitojun if (getaddrinfo(append_dot(host->name), "0", &hints, &res0) == 0)
19174a87116Sitojun #else
19274a87116Sitojun if (getaddrinfo(host->name, "0", &hints, &res0) == 0)
19374a87116Sitojun #endif
19474a87116Sitojun {
19574a87116Sitojun tcpd_warn("Nasty PTR record is configured");
19674a87116Sitojun freeaddrinfo(res0);
19774a87116Sitojun /* name is bad, clobber it */
19874a87116Sitojun (void)strlcpy(host->name, paranoid, sizeof(host->name));
19974a87116Sitojun return;
20074a87116Sitojun }
20174a87116Sitojun
20274a87116Sitojun /*
203541be36cSmrg * Verify that the address is a member of the address list returned
2042f7d82e6Sitojun * by getaddrinfo(hostname).
205541be36cSmrg *
2062f7d82e6Sitojun * Verify also that getnameinfo() and getaddrinfo() return the same
207541be36cSmrg * hostname, or rshd and rlogind may still end up being spoofed.
208541be36cSmrg *
2092f7d82e6Sitojun * On some sites, getaddrinfo("localhost") returns "localhost.domain".
210541be36cSmrg * This is a DNS artefact. We treat it as a special case. When we
2112f7d82e6Sitojun * can't believe the address list from getaddrinfo("localhost")
212541be36cSmrg * we're in big trouble anyway.
213541be36cSmrg */
2142f7d82e6Sitojun memset(&hints, 0, sizeof(hints));
2152f7d82e6Sitojun hints.ai_family = sa->sa_family;
2162f7d82e6Sitojun hints.ai_socktype = SOCK_DGRAM; /*dummy*/
2172f7d82e6Sitojun hints.ai_flags = AI_CANONNAME;
21844772e4bSitojun #ifdef APPEND_DOT
21944772e4bSitojun if (getaddrinfo(append_dot(host->name), "0", &hints, &res0) != 0)
22044772e4bSitojun #else
22144772e4bSitojun if (getaddrinfo(host->name, "0", &hints, &res0) != 0)
22244772e4bSitojun #endif
22344772e4bSitojun {
224541be36cSmrg /*
225541be36cSmrg * Unable to verify that the host name matches the address. This
226541be36cSmrg * may be a transient problem or a botched name server setup.
227541be36cSmrg */
228541be36cSmrg
2292f7d82e6Sitojun tcpd_warn("can't verify hostname: getaddrinfo(%s, %d) failed",
2302f7d82e6Sitojun host->name, hints.ai_family);
2312f7d82e6Sitojun } else if (res0->ai_canonname &&
2322f7d82e6Sitojun STR_NE(host->name, res0->ai_canonname) &&
2332f7d82e6Sitojun STR_NE(host->name, "localhost")) {
234541be36cSmrg /*
2352f7d82e6Sitojun * The getnameinfo() and getaddrinfo() calls did not return
236541be36cSmrg * the same hostname. This could be a nameserver configuration
237541be36cSmrg * problem. It could also be that someone is trying to spoof us.
238541be36cSmrg */
239541be36cSmrg
2402f7d82e6Sitojun tcpd_warn("host name/name mismatch: %s != %s",
2412f7d82e6Sitojun host->name, res0->ai_canonname);
2422f7d82e6Sitojun freeaddrinfo(res0);
243541be36cSmrg } else {
244541be36cSmrg /*
245541be36cSmrg * The address should be a member of the address list returned by
2462f7d82e6Sitojun * getaddrinfo().
247541be36cSmrg */
248541be36cSmrg
2492f7d82e6Sitojun for (res = res0; res; res = res->ai_next) {
2502f7d82e6Sitojun if (getnameinfo(res->ai_addr, res->ai_addrlen, h2, sizeof(h2),
2512f7d82e6Sitojun NULL, 0, NI_NUMERICHOST) != 0) {
2522f7d82e6Sitojun continue;
2532f7d82e6Sitojun }
2542f7d82e6Sitojun if (STR_EQ(h1, h2)) {
2552f7d82e6Sitojun freeaddrinfo(res0);
2562f7d82e6Sitojun return;
2572f7d82e6Sitojun }
258541be36cSmrg }
259541be36cSmrg
260541be36cSmrg /*
261541be36cSmrg * The host name does not map to the initial address. Perhaps
262541be36cSmrg * someone has messed up. Perhaps someone compromised a name
263541be36cSmrg * server.
264541be36cSmrg */
265541be36cSmrg
2662f7d82e6Sitojun tcpd_warn("host name/address mismatch: %s != %s", h1,
2672f7d82e6Sitojun res0->ai_canonname ? res0->ai_canonname : "?");
2682f7d82e6Sitojun
2692f7d82e6Sitojun freeaddrinfo(res0);
270541be36cSmrg }
2719cd5492cSmrg /* name is bad, clobber it */
2723ba1803eSitojun (void)strlcpy(host->name, paranoid, sizeof(host->name));
273541be36cSmrg }
274541be36cSmrg }
275541be36cSmrg
276541be36cSmrg /* sock_sink - absorb unreceived IP datagram */
277541be36cSmrg
278*e1a2f47fSmatt static void
sock_sink(int fd)279*e1a2f47fSmatt sock_sink(int fd)
280541be36cSmrg {
281541be36cSmrg char buf[BUFSIZ];
2823ba1803eSitojun struct sockaddr_storage ss;
2830c37c63eSmrg socklen_t size = sizeof(ss);
284541be36cSmrg
285541be36cSmrg /*
286541be36cSmrg * Eat up the not-yet received datagram. Some systems insist on a
287541be36cSmrg * non-zero source address argument in the recvfrom() call below.
288541be36cSmrg */
289541be36cSmrg
2903ba1803eSitojun (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & ss, &size);
291541be36cSmrg }
292