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} 236