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 19: static char sccsid[] = "@(#) socket.c 1.14 95/01/30 19:51:50"; 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: 33: extern char *inet_ntoa(); 34: 35: /* Local stuff. */ 36: 37: #include "tcpd.h" 38: 39: /* Forward declarations. */ 40: 41: static 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: 51: static struct hostent *gethostbyname_dot(name) 52: char *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: 74: void sock_host(request) 75: struct 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: 125: void sock_hostaddr(host) 126: struct 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: 136: void sock_hostname(host) 137: struct 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, 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), 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: 222: static void sock_sink(fd) 223: int 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: }