1 /* $NetBSD: socket.c,v 1.10 2002/05/24 05:38:20 itojun Exp $ */ 2 3 /* 4 * This module determines the type of socket (datagram, stream), the client 5 * socket address and port, the server socket address and port. In addition, 6 * it provides methods to map a transport address to a printable host name 7 * or address. Socket address information results are in static memory. 8 * 9 * The result from the hostname lookup method is STRING_PARANOID when a host 10 * pretends to have someone elses name, or when a host name is available but 11 * could not be verified. 12 * 13 * When lookup or conversion fails the result is set to STRING_UNKNOWN. 14 * 15 * Diagnostics are reported through syslog(3). 16 * 17 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 18 */ 19 20 #include <sys/cdefs.h> 21 #ifndef lint 22 #if 0 23 static char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24"; 24 #else 25 __RCSID("$NetBSD: socket.c,v 1.10 2002/05/24 05:38:20 itojun Exp $"); 26 #endif 27 #endif 28 29 /* System libraries. */ 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/socket.h> 34 #include <netinet/in.h> 35 #include <netdb.h> 36 #include <stdio.h> 37 #include <syslog.h> 38 #include <string.h> 39 #include <arpa/inet.h> 40 41 /* Local stuff. */ 42 43 #include "tcpd.h" 44 45 /* Forward declarations. */ 46 47 static void sock_sink __P((int)); 48 49 /* sock_host - look up endpoint addresses and install conversion methods */ 50 51 void sock_host(request) 52 struct request_info *request; 53 { 54 static struct sockaddr_storage client; 55 static struct sockaddr_storage server; 56 int len; 57 char buf[BUFSIZ]; 58 int fd = request->fd; 59 60 sock_methods(request); 61 62 /* 63 * Look up the client host address. Hal R. Brand <BRAND@addvax.llnl.gov> 64 * suggested how to get the client host info in case of UDP connections: 65 * peek at the first message without actually looking at its contents. We 66 * really should verify that client.sin_family gets the value AF_INET, 67 * but this program has already caused too much grief on systems with 68 * broken library code. 69 * 70 * XXX the last sentence is untrue as we support AF_INET6 as well :-) 71 */ 72 73 len = sizeof(client); 74 if (getpeername(fd, (struct sockaddr *) & client, &len) < 0) { 75 request->sink = sock_sink; 76 len = sizeof(client); 77 if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK, 78 (struct sockaddr *) & client, &len) < 0) { 79 tcpd_warn("can't get client address: %m"); 80 return; /* give up */ 81 } 82 #ifdef really_paranoid 83 memset(buf, 0 sizeof(buf)); 84 #endif 85 } 86 request->client->sin = (struct sockaddr *)&client; 87 88 /* 89 * Determine the server binding. This is used for client username 90 * lookups, and for access control rules that trigger on the server 91 * address or name. 92 */ 93 94 len = sizeof(server); 95 if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) { 96 tcpd_warn("getsockname: %m"); 97 return; 98 } 99 request->server->sin = (struct sockaddr *)&server; 100 } 101 102 /* sock_hostaddr - map endpoint address to printable form */ 103 104 void sock_hostaddr(host) 105 struct host_info *host; 106 { 107 struct sockaddr *sa = host->sin; 108 int alen, af; 109 char *ap; 110 111 if (!sa) 112 return; 113 switch (af = sa->sa_family) { 114 case AF_INET: 115 ap = (char *)&((struct sockaddr_in *)sa)->sin_addr; 116 alen = sizeof(struct in_addr); 117 break; 118 #ifdef INET6 119 case AF_INET6: 120 ap = (char *)&((struct sockaddr_in6 *)sa)->sin6_addr; 121 alen = sizeof(struct in6_addr); 122 break; 123 #endif 124 default: 125 return; 126 } 127 host->addr[0] = '\0'; 128 inet_ntop(af, ap, host->addr, sizeof(host->addr)); 129 } 130 131 /* sock_hostname - map endpoint address to host name */ 132 133 void sock_hostname(host) 134 struct host_info *host; 135 { 136 struct sockaddr *sinp = host->sin; 137 struct hostent *hp; 138 int i; 139 int af, alen; 140 char *ap; 141 char hbuf[MAXHOSTNAMELEN]; 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 (!sinp) 151 return; 152 switch (af = sinp->sa_family) { 153 case AF_INET: 154 if (((struct sockaddr_in *)sinp)->sin_addr.s_addr == 0) 155 return; 156 ap = (char *)&((struct sockaddr_in *)sinp)->sin_addr; 157 alen = sizeof(struct in_addr); 158 break; 159 #ifdef INET6 160 case AF_INET6: 161 ap = (char *)&((struct sockaddr_in6 *)sinp)->sin6_addr; 162 alen = sizeof(struct in6_addr); 163 /* special case on reverse lookup: mapped addr. I hate it */ 164 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 165 af = AF_INET; 166 ap += (sizeof(struct in6_addr) - sizeof(struct in_addr)); 167 alen = sizeof(struct in_addr); 168 } 169 break; 170 #endif 171 default: 172 return; 173 } 174 if ((hp = gethostbyaddr(ap, alen, af)) != 0) { 175 176 STRN_CPY(host->name, hp->h_name, sizeof(host->name)); 177 178 /* 179 * Verify that the address is a member of the address list returned 180 * by gethostbyname(hostname). 181 * 182 * Verify also that gethostbyaddr() and gethostbyname() return the same 183 * hostname, or rshd and rlogind may still end up being spoofed. 184 * 185 * On some sites, gethostbyname("localhost") returns "localhost.domain". 186 * This is a DNS artefact. We treat it as a special case. When we 187 * can't believe the address list from gethostbyname("localhost") 188 * we're in big trouble anyway. 189 */ 190 191 if ((hp = gethostbyname2(host->name, af)) == 0) { 192 193 /* 194 * Unable to verify that the host name matches the address. This 195 * may be a transient problem or a botched name server setup. 196 */ 197 198 tcpd_warn("can't verify hostname: gethostbyname2(%s, %d) failed", 199 host->name, af); 200 201 } else if (STR_NE(host->name, hp->h_name) 202 && STR_NE(host->name, "localhost")) { 203 204 /* 205 * The gethostbyaddr() and gethostbyname() calls did not return 206 * the same hostname. This could be a nameserver configuration 207 * problem. It could also be that someone is trying to spoof us. 208 */ 209 210 tcpd_warn("host name/name mismatch: %s != %.*s", 211 host->name, STRING_LENGTH, hp->h_name); 212 213 } else { 214 215 /* 216 * The address should be a member of the address list returned by 217 * gethostbyname(). We should first verify that the h_addrtype 218 * field is AF_INET, but this program has already caused too much 219 * grief on systems with broken library code. 220 */ 221 222 for (i = 0; hp->h_addr_list[i]; i++) { 223 if (memcmp(hp->h_addr_list[i], (char *) ap, alen) == 0) 224 return; /* name is good, keep it */ 225 } 226 227 /* 228 * The host name does not map to the initial address. Perhaps 229 * someone has messed up. Perhaps someone compromised a name 230 * server. 231 */ 232 233 tcpd_warn("host name/address mismatch: %s != %.*s", 234 inet_ntop(af, ap, hbuf, sizeof(hbuf)), 235 STRING_LENGTH, hp->h_name); 236 } 237 /* name is bad, clobber it */ 238 (void)strncpy(host->name, paranoid, sizeof(host->name) - 1); 239 } 240 } 241 242 /* sock_sink - absorb unreceived IP datagram */ 243 244 static void sock_sink(fd) 245 int fd; 246 { 247 char buf[BUFSIZ]; 248 struct sockaddr_storage sst; 249 int size = sizeof(sst); 250 251 /* 252 * Eat up the not-yet received datagram. Some systems insist on a 253 * non-zero source address argument in the recvfrom() call below. 254 */ 255 256 (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & sst, &size); 257 } 258