1 1.19 matt /* $NetBSD: socket.c,v 1.19 2012/03/21 10:10:37 matt Exp $ */ 2 1.3 christos 3 1.1 mrg /* 4 1.1 mrg * This module determines the type of socket (datagram, stream), the client 5 1.1 mrg * socket address and port, the server socket address and port. In addition, 6 1.1 mrg * it provides methods to map a transport address to a printable host name 7 1.1 mrg * or address. Socket address information results are in static memory. 8 1.5 simonb * 9 1.1 mrg * The result from the hostname lookup method is STRING_PARANOID when a host 10 1.1 mrg * pretends to have someone elses name, or when a host name is available but 11 1.1 mrg * could not be verified. 12 1.5 simonb * 13 1.1 mrg * When lookup or conversion fails the result is set to STRING_UNKNOWN. 14 1.5 simonb * 15 1.1 mrg * Diagnostics are reported through syslog(3). 16 1.5 simonb * 17 1.1 mrg * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 18 1.1 mrg */ 19 1.1 mrg 20 1.3 christos #include <sys/cdefs.h> 21 1.1 mrg #ifndef lint 22 1.3 christos #if 0 23 1.6 itojun static char sccsid[] = "@(#) socket.c 1.15 97/03/21 19:27:24"; 24 1.3 christos #else 25 1.19 matt __RCSID("$NetBSD: socket.c,v 1.19 2012/03/21 10:10:37 matt Exp $"); 26 1.3 christos #endif 27 1.1 mrg #endif 28 1.1 mrg 29 1.1 mrg /* System libraries. */ 30 1.1 mrg 31 1.1 mrg #include <sys/types.h> 32 1.1 mrg #include <sys/param.h> 33 1.1 mrg #include <sys/socket.h> 34 1.1 mrg #include <netinet/in.h> 35 1.1 mrg #include <netdb.h> 36 1.1 mrg #include <stdio.h> 37 1.1 mrg #include <syslog.h> 38 1.1 mrg #include <string.h> 39 1.3 christos #include <arpa/inet.h> 40 1.1 mrg 41 1.1 mrg /* Local stuff. */ 42 1.1 mrg 43 1.1 mrg #include "tcpd.h" 44 1.1 mrg 45 1.1 mrg /* Forward declarations. */ 46 1.1 mrg 47 1.13 itojun #ifdef APPEND_DOT 48 1.13 itojun static const char *append_dot __P((const char *)); 49 1.13 itojun #endif 50 1.3 christos static void sock_sink __P((int)); 51 1.1 mrg 52 1.13 itojun #ifdef APPEND_DOT 53 1.13 itojun /* 54 1.13 itojun * Speed up DNS lookups by terminating the host name with a dot. Should be 55 1.13 itojun * done with care. The speedup can give problems with lookups from sources 56 1.13 itojun * that lack DNS-style trailing dot magic, such as local files or NIS maps. 57 1.13 itojun */ 58 1.13 itojun 59 1.13 itojun static const char * 60 1.13 itojun append_dot(name) 61 1.14 itojun const char *name; 62 1.13 itojun { 63 1.13 itojun static char hbuf[MAXHOSTNAMELEN + 1]; 64 1.13 itojun 65 1.13 itojun /* 66 1.13 itojun * Don't append dots to unqualified names. Such names are likely to come 67 1.13 itojun * from local hosts files or from NIS. 68 1.13 itojun */ 69 1.13 itojun 70 1.13 itojun if (strchr(name, '.') == 0 || strlen(name) + 2 > sizeof(hbuf)) 71 1.13 itojun strlcpy(hbuf, name, sizeof(hbuf)); 72 1.13 itojun else 73 1.13 itojun (void)snprintf(hbuf, sizeof(hbuf), "%s.", name); 74 1.13 itojun return hbuf; 75 1.13 itojun } 76 1.13 itojun #endif 77 1.13 itojun 78 1.1 mrg /* sock_host - look up endpoint addresses and install conversion methods */ 79 1.1 mrg 80 1.19 matt void 81 1.19 matt sock_host(struct request_info *request) 82 1.1 mrg { 83 1.7 itojun static struct sockaddr_storage client; 84 1.7 itojun static struct sockaddr_storage server; 85 1.18 mrg socklen_t len; 86 1.1 mrg char buf[BUFSIZ]; 87 1.1 mrg int fd = request->fd; 88 1.1 mrg 89 1.1 mrg sock_methods(request); 90 1.1 mrg 91 1.1 mrg /* 92 1.1 mrg * Look up the client host address. Hal R. Brand <BRAND (at) addvax.llnl.gov> 93 1.1 mrg * suggested how to get the client host info in case of UDP connections: 94 1.1 mrg * peek at the first message without actually looking at its contents. We 95 1.1 mrg * really should verify that client.sin_family gets the value AF_INET, 96 1.1 mrg * but this program has already caused too much grief on systems with 97 1.1 mrg * broken library code. 98 1.7 itojun * 99 1.7 itojun * XXX the last sentence is untrue as we support AF_INET6 as well :-) 100 1.1 mrg */ 101 1.1 mrg 102 1.16 thorpej if (request->client->sin == NULL) { 103 1.16 thorpej len = sizeof(client); 104 1.18 mrg if (getpeername(fd, (struct sockaddr *)(void *)& client, &len) < 0) { 105 1.16 thorpej request->sink = sock_sink; 106 1.16 thorpej len = sizeof(client); 107 1.16 thorpej if (recvfrom(fd, buf, sizeof(buf), MSG_PEEK, 108 1.16 thorpej (struct sockaddr *) & client, &len) < 0) { 109 1.16 thorpej tcpd_warn("can't get client address: %m"); 110 1.16 thorpej return; /* give up */ 111 1.16 thorpej } 112 1.1 mrg #ifdef really_paranoid 113 1.16 thorpej memset(buf, 0, sizeof(buf)); 114 1.1 mrg #endif 115 1.16 thorpej } 116 1.16 thorpej request->client->sin = (struct sockaddr *)&client; 117 1.1 mrg } 118 1.1 mrg 119 1.1 mrg /* 120 1.1 mrg * Determine the server binding. This is used for client username 121 1.1 mrg * lookups, and for access control rules that trigger on the server 122 1.1 mrg * address or name. 123 1.1 mrg */ 124 1.1 mrg 125 1.16 thorpej if (request->server->sin == NULL) { 126 1.16 thorpej len = sizeof(server); 127 1.16 thorpej if (getsockname(fd, (struct sockaddr *) & server, &len) < 0) { 128 1.16 thorpej tcpd_warn("getsockname: %m"); 129 1.16 thorpej return; 130 1.16 thorpej } 131 1.16 thorpej request->server->sin = (struct sockaddr *)&server; 132 1.1 mrg } 133 1.1 mrg } 134 1.1 mrg 135 1.1 mrg /* sock_hostaddr - map endpoint address to printable form */ 136 1.1 mrg 137 1.19 matt void 138 1.19 matt sock_hostaddr(struct host_info *host) 139 1.1 mrg { 140 1.7 itojun struct sockaddr *sa = host->sin; 141 1.1 mrg 142 1.7 itojun if (!sa) 143 1.7 itojun return; 144 1.7 itojun host->addr[0] = '\0'; 145 1.11 itojun getnameinfo(sa, sa->sa_len, host->addr, sizeof(host->addr), 146 1.11 itojun NULL, 0, NI_NUMERICHOST); 147 1.1 mrg } 148 1.1 mrg 149 1.1 mrg /* sock_hostname - map endpoint address to host name */ 150 1.1 mrg 151 1.19 matt void 152 1.19 matt sock_hostname(struct host_info *host) 153 1.1 mrg { 154 1.11 itojun struct sockaddr *sa = host->sin; 155 1.11 itojun char h1[NI_MAXHOST], h2[NI_MAXHOST]; 156 1.11 itojun struct addrinfo hints, *res, *res0; 157 1.11 itojun #ifdef INET6 158 1.11 itojun struct sockaddr_in tmp; 159 1.11 itojun #endif 160 1.1 mrg 161 1.11 itojun if (!sa) 162 1.7 itojun return; 163 1.7 itojun #ifdef INET6 164 1.11 itojun /* special case on reverse lookup: mapped addr. I hate it */ 165 1.11 itojun if (sa->sa_family == AF_INET6 && 166 1.11 itojun IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) { 167 1.11 itojun memset(&tmp, 0, sizeof(tmp)); 168 1.11 itojun tmp.sin_family = AF_INET; 169 1.11 itojun tmp.sin_len = sizeof(struct sockaddr_in); 170 1.11 itojun memcpy(&tmp.sin_addr, 171 1.11 itojun &((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[12], 4); 172 1.11 itojun sa = (struct sockaddr *)&tmp; 173 1.11 itojun } 174 1.7 itojun #endif 175 1.11 itojun if (getnameinfo(sa, sa->sa_len, h1, sizeof(h1), NULL, 0, 176 1.11 itojun NI_NUMERICHOST) != 0) { 177 1.7 itojun return; 178 1.7 itojun } 179 1.11 itojun if (getnameinfo(sa, sa->sa_len, host->name, sizeof(host->name), NULL, 0, 180 1.11 itojun NI_NAMEREQD) == 0) { 181 1.17 itojun /* 182 1.17 itojun * if reverse lookup result looks like a numeric hostname, 183 1.17 itojun * someone is trying to trick us by PTR record like following: 184 1.17 itojun * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 185 1.17 itojun */ 186 1.17 itojun memset(&hints, 0, sizeof(hints)); 187 1.17 itojun hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 188 1.17 itojun hints.ai_flags = AI_NUMERICHOST; 189 1.17 itojun #ifdef APPEND_DOT 190 1.17 itojun if (getaddrinfo(append_dot(host->name), "0", &hints, &res0) == 0) 191 1.17 itojun #else 192 1.17 itojun if (getaddrinfo(host->name, "0", &hints, &res0) == 0) 193 1.17 itojun #endif 194 1.17 itojun { 195 1.17 itojun tcpd_warn("Nasty PTR record is configured"); 196 1.17 itojun freeaddrinfo(res0); 197 1.17 itojun /* name is bad, clobber it */ 198 1.17 itojun (void)strlcpy(host->name, paranoid, sizeof(host->name)); 199 1.17 itojun return; 200 1.17 itojun } 201 1.17 itojun 202 1.1 mrg /* 203 1.1 mrg * Verify that the address is a member of the address list returned 204 1.11 itojun * by getaddrinfo(hostname). 205 1.5 simonb * 206 1.11 itojun * Verify also that getnameinfo() and getaddrinfo() return the same 207 1.1 mrg * hostname, or rshd and rlogind may still end up being spoofed. 208 1.5 simonb * 209 1.11 itojun * On some sites, getaddrinfo("localhost") returns "localhost.domain". 210 1.1 mrg * This is a DNS artefact. We treat it as a special case. When we 211 1.11 itojun * can't believe the address list from getaddrinfo("localhost") 212 1.1 mrg * we're in big trouble anyway. 213 1.1 mrg */ 214 1.11 itojun memset(&hints, 0, sizeof(hints)); 215 1.11 itojun hints.ai_family = sa->sa_family; 216 1.11 itojun hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 217 1.11 itojun hints.ai_flags = AI_CANONNAME; 218 1.13 itojun #ifdef APPEND_DOT 219 1.13 itojun if (getaddrinfo(append_dot(host->name), "0", &hints, &res0) != 0) 220 1.13 itojun #else 221 1.13 itojun if (getaddrinfo(host->name, "0", &hints, &res0) != 0) 222 1.13 itojun #endif 223 1.13 itojun { 224 1.1 mrg /* 225 1.1 mrg * Unable to verify that the host name matches the address. This 226 1.1 mrg * may be a transient problem or a botched name server setup. 227 1.1 mrg */ 228 1.1 mrg 229 1.11 itojun tcpd_warn("can't verify hostname: getaddrinfo(%s, %d) failed", 230 1.11 itojun host->name, hints.ai_family); 231 1.11 itojun } else if (res0->ai_canonname && 232 1.11 itojun STR_NE(host->name, res0->ai_canonname) && 233 1.11 itojun STR_NE(host->name, "localhost")) { 234 1.1 mrg /* 235 1.11 itojun * The getnameinfo() and getaddrinfo() calls did not return 236 1.1 mrg * the same hostname. This could be a nameserver configuration 237 1.1 mrg * problem. It could also be that someone is trying to spoof us. 238 1.1 mrg */ 239 1.1 mrg 240 1.11 itojun tcpd_warn("host name/name mismatch: %s != %s", 241 1.11 itojun host->name, res0->ai_canonname); 242 1.11 itojun freeaddrinfo(res0); 243 1.1 mrg } else { 244 1.1 mrg /* 245 1.1 mrg * The address should be a member of the address list returned by 246 1.11 itojun * getaddrinfo(). 247 1.1 mrg */ 248 1.1 mrg 249 1.11 itojun for (res = res0; res; res = res->ai_next) { 250 1.11 itojun if (getnameinfo(res->ai_addr, res->ai_addrlen, h2, sizeof(h2), 251 1.11 itojun NULL, 0, NI_NUMERICHOST) != 0) { 252 1.11 itojun continue; 253 1.11 itojun } 254 1.11 itojun if (STR_EQ(h1, h2)) { 255 1.11 itojun freeaddrinfo(res0); 256 1.11 itojun return; 257 1.11 itojun } 258 1.1 mrg } 259 1.1 mrg 260 1.1 mrg /* 261 1.1 mrg * The host name does not map to the initial address. Perhaps 262 1.1 mrg * someone has messed up. Perhaps someone compromised a name 263 1.1 mrg * server. 264 1.1 mrg */ 265 1.1 mrg 266 1.11 itojun tcpd_warn("host name/address mismatch: %s != %s", h1, 267 1.11 itojun res0->ai_canonname ? res0->ai_canonname : "?"); 268 1.11 itojun 269 1.11 itojun freeaddrinfo(res0); 270 1.1 mrg } 271 1.2 mrg /* name is bad, clobber it */ 272 1.12 itojun (void)strlcpy(host->name, paranoid, sizeof(host->name)); 273 1.1 mrg } 274 1.1 mrg } 275 1.1 mrg 276 1.1 mrg /* sock_sink - absorb unreceived IP datagram */ 277 1.1 mrg 278 1.19 matt static void 279 1.19 matt sock_sink(int fd) 280 1.1 mrg { 281 1.1 mrg char buf[BUFSIZ]; 282 1.12 itojun struct sockaddr_storage ss; 283 1.18 mrg socklen_t size = sizeof(ss); 284 1.1 mrg 285 1.1 mrg /* 286 1.1 mrg * Eat up the not-yet received datagram. Some systems insist on a 287 1.1 mrg * non-zero source address argument in the recvfrom() call below. 288 1.1 mrg */ 289 1.1 mrg 290 1.12 itojun (void) recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *) & ss, &size); 291 1.1 mrg } 292