source: trunk/third/tcp_wrappers/socket.c @ 11717

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