Deleted Added
full compact
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 * $FreeBSD: head/contrib/tcp_wrappers/socket.c 56977 2000-02-03 10:27:03Z shin $
18 */
19
20#ifndef lint
21static char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24";
22#endif
23
24/* System libraries. */
25
26#include <sys/types.h>
27#include <sys/param.h>
28#include <sys/socket.h>
29#include <netinet/in.h>
30#include <netdb.h>
31#include <stdio.h>
32#include <syslog.h>
33#include <string.h>
34
35#ifdef INET6
36#ifndef USE_GETIPNODEBY
37#include <resolv.h>
38#endif
39#endif
40
41extern char *inet_ntoa();
42
43/* Local stuff. */
44
45#include "tcpd.h"
46
47/* Forward declarations. */
48

--- 28 unchanged lines hidden (view full) ---

77#define gethostbyname gethostbyname_dot
78#endif
79
80/* sock_host - look up endpoint addresses and install conversion methods */
81
82void sock_host(request)
83struct request_info *request;
84{
85#ifdef INET6
86 static struct sockaddr_storage client;
87 static struct sockaddr_storage server;
88#else
89 static struct sockaddr_in client;
90 static struct sockaddr_in server;
91#endif
92 int len;
93 char buf[BUFSIZ];
94 int fd = request->fd;
95
96 sock_methods(request);
97
98 /*
99 * Look up the client host address. Hal R. Brand <BRAND@addvax.llnl.gov>

--- 12 unchanged lines hidden (view full) ---

112 (struct sockaddr *) & client, &len) < 0) {
113 tcpd_warn("can't get client address: %m");
114 return; /* give up */
115 }
116#ifdef really_paranoid
117 memset(buf, 0 sizeof(buf));
118#endif
119 }
120#ifdef INET6
121 request->client->sin = (struct sockaddr *)&client;
122#else
123 request->client->sin = &client;
124#endif
125
126 /*
127 * Determine the server binding. This is used for client username
128 * lookups, and for access control rules that trigger on the server
129 * address or name.
130 */
131
132 len = sizeof(server);
133 if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) {
134 tcpd_warn("getsockname: %m");
135 return;
136 }
137#ifdef INET6
138 request->server->sin = (struct sockaddr *)&server;
139#else
140 request->server->sin = &server;
141#endif
142}
143
144/* sock_hostaddr - map endpoint address to printable form */
145
146void sock_hostaddr(host)
147struct host_info *host;
148{
149#ifdef INET6
150 struct sockaddr *sin = host->sin;
151 char *ap;
152 int alen;
153
154 if (!sin)
155 return;
156 switch (sin->sa_family) {
157 case AF_INET:
158 ap = (char *)&((struct sockaddr_in *)sin)->sin_addr;
159 alen = sizeof(struct in_addr);
160 break;
161 case AF_INET6:
162 ap = (char *)&((struct sockaddr_in6 *)sin)->sin6_addr;
163 alen = sizeof(struct in6_addr);
164 break;
165 default:
166 return;
167 }
168 host->addr[0] = '\0';
169 inet_ntop(sin->sa_family, ap, host->addr, sizeof(host->addr));
170#else
171 struct sockaddr_in *sin = host->sin;
172
173 if (sin != 0)
174 STRN_CPY(host->addr, inet_ntoa(sin->sin_addr), sizeof(host->addr));
175#endif
176}
177
178/* sock_hostname - map endpoint address to host name */
179
180void sock_hostname(host)
181struct host_info *host;
182{
183#ifdef INET6
184 struct sockaddr *sin = host->sin;
185 char addr[128];
186#ifdef USE_GETIPNODEBY
187 int h_error;
188#else
189 u_long res_options;
190#endif
191 struct hostent *hp = NULL;
192 char *ap;
193 int alen;
194#else
195 struct sockaddr_in *sin = host->sin;
196 struct hostent *hp;
197#endif
198 int i;
199
200 /*
201 * On some systems, for example Solaris 2.3, gethostbyaddr(0.0.0.0) does
202 * not fail. Instead it returns "INADDR_ANY". Unfortunately, this does
203 * not work the other way around: gethostbyname("INADDR_ANY") fails. We
204 * have to special-case 0.0.0.0, in order to avoid false alerts from the
205 * host name/address checking code below.
206 */
207#ifdef INET6
208 if (sin != NULL) {
209 switch (sin->sa_family) {
210 case AF_INET:
211 if (((struct sockaddr_in *)sin)->sin_addr.s_addr == 0) {
212 strcpy(host->name, paranoid); /* name is bad, clobber it */
213 return;
214 }
215 ap = (char *) &((struct sockaddr_in *)sin)->sin_addr;
216 alen = sizeof(struct in_addr);
217 break;
218 case AF_INET6:
219 ap = (char *) &((struct sockaddr_in6 *)sin)->sin6_addr;
220 alen = sizeof(struct in6_addr);
221 break;
222 defalut:
223 strcpy(host->name, paranoid); /* name is bad, clobber it */
224 return;
225 }
226#ifdef USE_GETIPNODEBY
227 hp = getipnodebyaddr(ap, alen, sin->sa_family, &h_error);
228#else
229 hp = gethostbyaddr(ap, alen, sin->sa_family);
230#endif
231 }
232 if (hp) {
233#else
234 if (sin != 0 && sin->sin_addr.s_addr != 0
235 && (hp = gethostbyaddr((char *) &(sin->sin_addr),
236 sizeof(sin->sin_addr), AF_INET)) != 0) {
237#endif
238
239 STRN_CPY(host->name, hp->h_name, sizeof(host->name));
240#if defined(INET6) && defined(USE_GETIPNODEBY)
241 freehostent(hp);
242#endif
243
244 /*
245 * Verify that the address is a member of the address list returned
246 * by gethostbyname(hostname).
247 *
248 * Verify also that gethostbyaddr() and gethostbyname() return the same
249 * hostname, or rshd and rlogind may still end up being spoofed.
250 *
251 * On some sites, gethostbyname("localhost") returns "localhost.domain".
252 * This is a DNS artefact. We treat it as a special case. When we
253 * can't believe the address list from gethostbyname("localhost")
254 * we're in big trouble anyway.
255 */
256
257#ifdef INET6
258#ifdef USE_GETIPNODEBY
259 hp = getipnodebyname(host->name, sin->sa_family,
260 AI_V4MAPPED | AI_ADDRCONFIG | AI_ALL, &h_error);
261#else
262 if ((_res.options & RES_INIT) == 0) {
263 if (res_init() < 0) {
264 inet_ntop(sin->sa_family, ap, addr, sizeof(addr));
265 tcpd_warn("can't verify hostname: res_init() for %s failed",
266 addr);
267 strcpy(host->name, paranoid); /* name is bad, clobber it */
268 return;
269 }
270 }
271 res_options = _res.options;
272 if (sin->sa_family == AF_INET6)
273 _res.options |= RES_USE_INET6;
274 else
275 _res.options &= ~RES_USE_INET6;
276 hp = gethostbyname2(host->name,
277 (sin->sa_family == AF_INET6 &&
278 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sin)->sin6_addr)) ?
279 AF_INET : sin->sa_family);
280 _res.options = res_options;
281#endif
282 if (!hp) {
283#else
284 if ((hp = gethostbyname(host->name)) == 0) {
285#endif
286
287 /*
288 * Unable to verify that the host name matches the address. This
289 * may be a transient problem or a botched name server setup.
290 */
291
292#ifdef INET6
293#ifdef USE_GETIPNODEBY
294 tcpd_warn("can't verify hostname: getipnodebyname(%s, %s) failed",
295#else
296 tcpd_warn("can't verify hostname: gethostbyname2(%s, %s) failed",
297#endif
298 host->name,
299 (sin->sa_family == AF_INET) ? "AF_INET" : "AF_INET6");
300#else
301 tcpd_warn("can't verify hostname: gethostbyname(%s) failed",
302 host->name);
303#endif
304
305 } else if (STR_NE(host->name, hp->h_name)
306 && STR_NE(host->name, "localhost")) {
307
308 /*
309 * The gethostbyaddr() and gethostbyname() calls did not return
310 * the same hostname. This could be a nameserver configuration
311 * problem. It could also be that someone is trying to spoof us.

--- 7 unchanged lines hidden (view full) ---

319 /*
320 * The address should be a member of the address list returned by
321 * gethostbyname(). We should first verify that the h_addrtype
322 * field is AF_INET, but this program has already caused too much
323 * grief on systems with broken library code.
324 */
325
326 for (i = 0; hp->h_addr_list[i]; i++) {
327#ifdef INET6
328 if (memcmp(hp->h_addr_list[i], ap, alen) == 0) {
329#ifdef USE_GETIPNODEBY
330 freehostent(hp);
331#endif
332 return; /* name is good, keep it */
333 }
334#else
335 if (memcmp(hp->h_addr_list[i],
336 (char *) &sin->sin_addr,
337 sizeof(sin->sin_addr)) == 0)
338 return; /* name is good, keep it */
339#endif
340 }
341
342 /*
343 * The host name does not map to the initial address. Perhaps
344 * someone has messed up. Perhaps someone compromised a name
345 * server.
346 */
347
348#ifdef INET6
349 inet_ntop(sin->sa_family, ap, addr, sizeof(addr));
350 tcpd_warn("host name/address mismatch: %s != %.*s",
351 addr, STRING_LENGTH, hp->h_name);
352#else
353 tcpd_warn("host name/address mismatch: %s != %.*s",
354 inet_ntoa(sin->sin_addr), STRING_LENGTH, hp->h_name);
355#endif
356 }
357 strcpy(host->name, paranoid); /* name is bad, clobber it */
358#if defined(INET6) && defined(USE_GETIPNODEBY)
359 if (hp)
360 freehostent(hp);
361#endif
362 }
363}
364
365/* sock_sink - absorb unreceived IP datagram */
366
367static void sock_sink(fd)
368int fd;
369{
370 char buf[BUFSIZ];
371#ifdef INET6
372 struct sockaddr_storage sin;
373#else
374 struct sockaddr_in sin;
375#endif
376 int size = sizeof(sin);
377
378 /*
379 * Eat up the not-yet received datagram. Some systems insist on a
380 * non-zero source address argument in the recvfrom() call below.
381 */
382
383 (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sin, &size);
384}