Annotation of embedaddon/rsync/clientname.c, revision 1.1.1.4
1.1 misho 1: /*
2: * Functions for looking up the remote name or addr of a socket.
3: *
4: * Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
5: * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
1.1.1.4 ! misho 6: * Copyright (C) 2002-2020 Wayne Davison
1.1 misho 7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: /*
23: * This file is now converted to use the new-style getaddrinfo()
24: * interface, which supports IPv6 but is also supported on recent
25: * IPv4-only machines. On systems that don't have that interface, we
26: * emulate it using the KAME implementation.
27: */
28:
29: #include "rsync.h"
1.1.1.4 ! misho 30: #include "itypes.h"
! 31:
! 32: extern int am_daemon;
1.1 misho 33:
34: static const char default_name[] = "UNKNOWN";
1.1.1.4 ! misho 35: static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n";
1.1 misho 36:
1.1.1.4 ! misho 37: static char ipaddr_buf[100];
1.1 misho 38:
1.1.1.4 ! misho 39: #define PROXY_V2_SIG_SIZE ((int)sizeof proxyv2sig - 1)
! 40: #define PROXY_V2_HEADER_SIZE (PROXY_V2_SIG_SIZE + 1 + 1 + 2)
! 41:
! 42: #define CMD_LOCAL 0
! 43: #define CMD_PROXY 1
! 44:
! 45: #define PROXY_FAM_TCPv4 0x11
! 46: #define PROXY_FAM_TCPv6 0x21
! 47:
! 48: #define GET_SOCKADDR_FAMILY(ss) ((struct sockaddr*)ss)->sa_family
! 49:
! 50: static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len);
! 51: static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size);
! 52: static int valid_ipaddr(const char *s);
! 53:
! 54: /* Return the IP addr of the client as a string. */
1.1 misho 55: char *client_addr(int fd)
56: {
57: struct sockaddr_storage ss;
58: socklen_t length = sizeof ss;
59:
1.1.1.4 ! misho 60: if (*ipaddr_buf)
! 61: return ipaddr_buf;
1.1 misho 62:
1.1.1.4 ! misho 63: if (am_daemon < 0) { /* daemon over --rsh mode */
1.1.1.2 misho 64: char *env_str;
1.1.1.4 ! misho 65: strlcpy(ipaddr_buf, "0.0.0.0", sizeof ipaddr_buf);
1.1.1.2 misho 66: if ((env_str = getenv("REMOTE_HOST")) != NULL
67: || (env_str = getenv("SSH_CONNECTION")) != NULL
68: || (env_str = getenv("SSH_CLIENT")) != NULL
69: || (env_str = getenv("SSH2_CLIENT")) != NULL) {
70: char *p;
1.1.1.4 ! misho 71: strlcpy(ipaddr_buf, env_str, sizeof ipaddr_buf);
1.1 misho 72: /* Truncate the value to just the IP address. */
1.1.1.4 ! misho 73: if ((p = strchr(ipaddr_buf, ' ')) != NULL)
1.1 misho 74: *p = '\0';
75: }
1.1.1.4 ! misho 76: if (valid_ipaddr(ipaddr_buf))
! 77: return ipaddr_buf;
1.1 misho 78: }
79:
1.1.1.4 ! misho 80: client_sockaddr(fd, &ss, &length);
! 81: getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST);
1.1 misho 82:
1.1.1.4 ! misho 83: return ipaddr_buf;
1.1 misho 84: }
85:
86:
87: /**
88: * Return the DNS name of the client.
89: *
90: * The name is statically cached so that repeated lookups are quick,
91: * so there is a limit of one lookup per customer.
92: *
93: * If anything goes wrong, including the name->addr->name check, then
94: * we just use "UNKNOWN", so you can use that value in hosts allow
95: * lines.
96: *
97: * After translation from sockaddr to name we do a forward lookup to
98: * make sure nobody is spoofing PTR records.
99: **/
1.1.1.4 ! misho 100: char *client_name(const char *ipaddr)
1.1 misho 101: {
102: static char name_buf[100];
1.1.1.4 ! misho 103: char port_buf[100];
1.1 misho 104: struct sockaddr_storage ss;
105: socklen_t ss_len;
1.1.1.4 ! misho 106: struct addrinfo hint, *answer;
! 107: int err;
1.1 misho 108:
1.1.1.4 ! misho 109: if (*name_buf)
1.1 misho 110: return name_buf;
111:
112: strlcpy(name_buf, default_name, sizeof name_buf);
113:
1.1.1.4 ! misho 114: if (strcmp(ipaddr, "0.0.0.0") == 0)
! 115: return name_buf;
1.1 misho 116:
1.1.1.4 ! misho 117: memset(&ss, 0, sizeof ss);
! 118: memset(&hint, 0, sizeof hint);
1.1 misho 119:
120: #ifdef AI_NUMERICHOST
1.1.1.4 ! misho 121: hint.ai_flags = AI_NUMERICHOST;
1.1 misho 122: #endif
1.1.1.4 ! misho 123: hint.ai_socktype = SOCK_STREAM;
1.1 misho 124:
1.1.1.4 ! misho 125: if ((err = getaddrinfo(ipaddr, NULL, &hint, &answer)) != 0) {
! 126: rprintf(FLOG, "malformed address %s: %s\n", ipaddr, gai_strerror(err));
! 127: return name_buf;
! 128: }
1.1 misho 129:
1.1.1.4 ! misho 130: switch (answer->ai_family) {
! 131: case AF_INET:
! 132: ss_len = sizeof (struct sockaddr_in);
! 133: memcpy(&ss, answer->ai_addr, ss_len);
! 134: break;
1.1 misho 135: #ifdef INET6
1.1.1.4 ! misho 136: case AF_INET6:
! 137: ss_len = sizeof (struct sockaddr_in6);
! 138: memcpy(&ss, answer->ai_addr, ss_len);
! 139: break;
1.1 misho 140: #endif
1.1.1.4 ! misho 141: default:
! 142: NOISY_DEATH("Unknown ai_family value");
1.1 misho 143: }
1.1.1.4 ! misho 144: freeaddrinfo(answer);
1.1 misho 145:
1.1.1.4 ! misho 146: /* reverse lookup */
! 147: err = getnameinfo((struct sockaddr*)&ss, ss_len, name_buf, sizeof name_buf,
! 148: port_buf, sizeof port_buf, NI_NAMEREQD | NI_NUMERICSERV);
! 149: if (err) {
! 150: strlcpy(name_buf, default_name, sizeof name_buf);
! 151: rprintf(FLOG, "name lookup failed for %s: %s\n", ipaddr, gai_strerror(err));
! 152: } else
! 153: check_name(ipaddr, &ss, name_buf, sizeof name_buf);
1.1 misho 154:
155: return name_buf;
156: }
157:
158:
1.1.1.4 ! misho 159: /* Try to read a proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */
! 160: int read_proxy_protocol_header(int fd)
! 161: {
! 162: union {
! 163: struct {
! 164: char line[108];
! 165: } v1;
! 166: struct {
! 167: char sig[PROXY_V2_SIG_SIZE];
! 168: char ver_cmd;
! 169: char fam;
! 170: char len[2];
! 171: union {
! 172: struct {
! 173: char src_addr[4];
! 174: char dst_addr[4];
! 175: char src_port[2];
! 176: char dst_port[2];
! 177: } ip4;
! 178: struct {
! 179: char src_addr[16];
! 180: char dst_addr[16];
! 181: char src_port[2];
! 182: char dst_port[2];
! 183: } ip6;
! 184: struct {
! 185: char src_addr[108];
! 186: char dst_addr[108];
! 187: } unx;
! 188: } addr;
! 189: } v2;
! 190: } hdr;
! 191:
! 192: read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE);
! 193:
! 194: if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */
! 195: int ver, cmd, size;
! 196:
! 197: read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE);
! 198:
! 199: ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
! 200: cmd = (hdr.v2.ver_cmd & 0x0f);
! 201: size = (hdr.v2.len[0] << 8) + hdr.v2.len[1];
! 202:
! 203: if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr)
! 204: return 0;
! 205:
! 206: /* Grab all the remaining data in the binary request. */
! 207: read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size);
! 208:
! 209: switch (cmd) {
! 210: case CMD_PROXY:
! 211: switch (hdr.v2.fam) {
! 212: case PROXY_FAM_TCPv4:
! 213: if (size != sizeof hdr.v2.addr.ip4)
! 214: return 0;
! 215: inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf);
! 216: return valid_ipaddr(ipaddr_buf);
! 217: case PROXY_FAM_TCPv6:
! 218: if (size != sizeof hdr.v2.addr.ip6)
! 219: return 0;
! 220: inet_ntop(AF_INET6, hdr.v2.addr.ip6.src_addr, ipaddr_buf, sizeof ipaddr_buf);
! 221: return valid_ipaddr(ipaddr_buf);
! 222: default:
! 223: break;
! 224: }
! 225: /* For an unsupported protocol we'll ignore the proxy data (leaving ipaddr_buf unset)
! 226: * and accept the connection, which will get handled as a normal socket addr. */
! 227: return 1;
! 228: case CMD_LOCAL:
! 229: return 1;
! 230: default:
! 231: break;
! 232: }
! 233:
! 234: return 0;
! 235: }
! 236:
! 237: if (memcmp(hdr.v1.line, "PROXY", 5) == 0) { /* Proxy V1 */
! 238: char *endc, *sp, *p = hdr.v1.line + PROXY_V2_SIG_SIZE;
! 239: int port_chk;
! 240:
! 241: *p = '\0';
! 242: if (!strchr(hdr.v1.line, '\n')) {
! 243: while (1) {
! 244: read_buf(fd, p, 1);
! 245: if (*p++ == '\n')
! 246: break;
! 247: if (p - hdr.v1.line >= (int)sizeof hdr.v1.line - 1)
! 248: return 0;
! 249: }
! 250: *p = '\0';
! 251: }
! 252:
! 253: endc = strchr(hdr.v1.line, '\r');
! 254: if (!endc || endc[1] != '\n' || endc[2])
! 255: return 0;
! 256: *endc = '\0';
! 257:
! 258: p = hdr.v1.line + 5;
! 259:
! 260: if (!isSpace(p++))
! 261: return 0;
! 262: if (strncmp(p, "TCP4", 4) == 0)
! 263: p += 4;
! 264: else if (strncmp(p, "TCP6", 4) == 0)
! 265: p += 4;
! 266: else if (strncmp(p, "UNKNOWN", 7) == 0)
! 267: return 1;
! 268: else
! 269: return 0;
! 270:
! 271: if (!isSpace(p++))
! 272: return 0;
! 273:
! 274: if ((sp = strchr(p, ' ')) == NULL)
! 275: return 0;
! 276: *sp = '\0';
! 277: if (!valid_ipaddr(p))
! 278: return 0;
! 279: strlcpy(ipaddr_buf, p, sizeof ipaddr_buf); /* It will always fit when valid. */
! 280:
! 281: p = sp + 1;
! 282: if ((sp = strchr(p, ' ')) == NULL)
! 283: return 0;
! 284: *sp = '\0';
! 285: if (!valid_ipaddr(p))
! 286: return 0;
! 287: /* Ignore destination address. */
! 288:
! 289: p = sp + 1;
! 290: if ((sp = strchr(p, ' ')) == NULL)
! 291: return 0;
! 292: *sp = '\0';
! 293: port_chk = strtol(p, &endc, 10);
! 294: if (*endc || port_chk == 0)
! 295: return 0;
! 296: /* Ignore source port. */
! 297:
! 298: p = sp + 1;
! 299: port_chk = strtol(p, &endc, 10);
! 300: if (*endc || port_chk == 0)
! 301: return 0;
! 302: /* Ignore destination port. */
! 303:
! 304: return 1;
! 305: }
! 306:
! 307: return 0;
! 308: }
! 309:
1.1 misho 310:
311: /**
312: * Get the sockaddr for the client.
313: *
314: * If it comes in as an ipv4 address mapped into IPv6 format then we
315: * convert it back to a regular IPv4.
316: **/
1.1.1.4 ! misho 317: static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
1.1 misho 318: {
319: memset(ss, 0, sizeof *ss);
320:
321: if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
322: /* FIXME: Can we really not continue? */
323: rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
324: exit_cleanup(RERR_SOCKETIO);
325: }
326:
327: #ifdef INET6
1.1.1.4 ! misho 328: if (GET_SOCKADDR_FAMILY(ss) == AF_INET6
! 329: && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
1.1 misho 330: /* OK, so ss is in the IPv6 family, but it is really
331: * an IPv4 address: something like
332: * "::ffff:10.130.1.2". If we use it as-is, then the
333: * reverse lookup might fail or perhaps something else
334: * bad might happen. So instead we convert it to an
335: * equivalent address in the IPv4 address family. */
336: struct sockaddr_in6 sin6;
337: struct sockaddr_in *sin;
338:
339: memcpy(&sin6, ss, sizeof sin6);
340: sin = (struct sockaddr_in *)ss;
341: memset(sin, 0, sizeof *sin);
342: sin->sin_family = AF_INET;
343: *ss_len = sizeof (struct sockaddr_in);
344: #ifdef HAVE_SOCKADDR_IN_LEN
345: sin->sin_len = *ss_len;
346: #endif
347: sin->sin_port = sin6.sin6_port;
348:
349: /* There is a macro to extract the mapped part
350: * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
351: * to be present in the Linux headers. */
1.1.1.4 ! misho 352: memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr);
1.1 misho 353: }
354: #endif
355: }
356:
357:
358: /**
359: * Compare an addrinfo from the resolver to a sockinfo.
360: *
361: * Like strcmp, returns 0 for identical.
362: **/
1.1.1.4 ! misho 363: static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss)
1.1 misho 364: {
1.1.1.4 ! misho 365: int ss_family = GET_SOCKADDR_FAMILY(ss);
1.1 misho 366: const char fn[] = "compare_addrinfo_sockaddr";
367:
368: if (ai->ai_family != ss_family) {
369: rprintf(FLOG, "%s: response family %d != %d\n",
370: fn, ai->ai_family, ss_family);
371: return 1;
372: }
373:
374: /* The comparison method depends on the particular AF. */
375: if (ss_family == AF_INET) {
376: const struct sockaddr_in *sin1, *sin2;
377:
378: sin1 = (const struct sockaddr_in *) ss;
379: sin2 = (const struct sockaddr_in *) ai->ai_addr;
380:
1.1.1.4 ! misho 381: return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof sin1->sin_addr);
1.1 misho 382: }
383:
384: #ifdef INET6
385: if (ss_family == AF_INET6) {
386: const struct sockaddr_in6 *sin1, *sin2;
387:
388: sin1 = (const struct sockaddr_in6 *) ss;
389: sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
390:
1.1.1.4 ! misho 391: if (ai->ai_addrlen < (int)sizeof (struct sockaddr_in6)) {
1.1 misho 392: rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
393: fn, (int)ai->ai_addrlen);
394: return 1;
395: }
396:
1.1.1.4 ! misho 397: if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof sin1->sin6_addr))
1.1 misho 398: return 1;
399:
400: #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
401: if (sin1->sin6_scope_id != sin2->sin6_scope_id)
402: return 1;
403: #endif
404: return 0;
405: }
406: #endif /* INET6 */
407:
408: /* don't know */
409: return 1;
410: }
411:
412:
413: /**
414: * Do a forward lookup on @p name_buf and make sure it corresponds to
415: * @p ss -- otherwise we may be being spoofed. If we suspect we are,
416: * then we don't abort the connection but just emit a warning, and
417: * change @p name_buf to be "UNKNOWN".
418: *
419: * We don't do anything with the service when checking the name,
420: * because it doesn't seem that it could be spoofed in any way, and
421: * getaddrinfo on random service names seems to cause problems on AIX.
422: **/
1.1.1.4 ! misho 423: static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size)
1.1 misho 424: {
425: struct addrinfo hints, *res, *res0;
426: int error;
1.1.1.4 ! misho 427: int ss_family = GET_SOCKADDR_FAMILY(ss);
1.1 misho 428:
429: memset(&hints, 0, sizeof hints);
430: hints.ai_family = ss_family;
431: hints.ai_flags = AI_CANONNAME;
432: hints.ai_socktype = SOCK_STREAM;
433: error = getaddrinfo(name_buf, NULL, &hints, &res0);
434: if (error) {
435: rprintf(FLOG, "forward name lookup for %s failed: %s\n",
436: name_buf, gai_strerror(error));
437: strlcpy(name_buf, default_name, name_buf_size);
438: return error;
439: }
440:
441: /* Given all these results, we expect that one of them will be
442: * the same as ss. The comparison is a bit complicated. */
443: for (res = res0; res; res = res->ai_next) {
444: if (!compare_addrinfo_sockaddr(res, ss))
445: break; /* OK, identical */
446: }
447:
448: if (!res0) {
449: /* We hit the end of the list without finding an
450: * address that was the same as ss. */
451: rprintf(FLOG, "no known address for \"%s\": "
452: "spoofed address?\n", name_buf);
453: strlcpy(name_buf, default_name, name_buf_size);
454: } else if (res == NULL) {
455: /* We hit the end of the list without finding an
456: * address that was the same as ss. */
457: rprintf(FLOG, "%s is not a known address for \"%s\": "
1.1.1.4 ! misho 458: "spoofed address?\n", ipaddr, name_buf);
1.1 misho 459: strlcpy(name_buf, default_name, name_buf_size);
460: }
461:
462: freeaddrinfo(res0);
463: return 0;
464: }
1.1.1.4 ! misho 465:
! 466: /* Returns 1 for a valid IPv4 or IPv6 addr, or 0 for a bad one. */
! 467: static int valid_ipaddr(const char *s)
! 468: {
! 469: int i;
! 470:
! 471: if (strchr(s, ':') != NULL) { /* Only IPv6 has a colon. */
! 472: int count, saw_double_colon = 0;
! 473: int ipv4_at_end = 0;
! 474:
! 475: if (*s == ':') { /* A colon at the start must be a :: */
! 476: if (*++s != ':')
! 477: return 0;
! 478: saw_double_colon = 1;
! 479: s++;
! 480: }
! 481:
! 482: for (count = 0; count < 8; count++) {
! 483: if (!*s)
! 484: return saw_double_colon;
! 485:
! 486: if (strchr(s, ':') == NULL && strchr(s, '.') != NULL) {
! 487: if ((!saw_double_colon && count != 6) || (saw_double_colon && count > 6))
! 488: return 0;
! 489: ipv4_at_end = 1;
! 490: break;
! 491: }
! 492:
! 493: if (!isHexDigit(s++)) /* Need 1-4 hex digits */
! 494: return 0;
! 495: if (isHexDigit(s) && isHexDigit(++s) && isHexDigit(++s) && isHexDigit(++s))
! 496: return 0;
! 497:
! 498: if (*s == ':') {
! 499: if (!*++s)
! 500: return 0;
! 501: if (*s == ':') {
! 502: if (saw_double_colon)
! 503: return 0;
! 504: saw_double_colon = 1;
! 505: s++;
! 506: }
! 507: }
! 508: }
! 509:
! 510: if (!ipv4_at_end)
! 511: return !*s;
! 512: }
! 513:
! 514: /* IPv4 */
! 515: for (i = 0; i < 4; i++) {
! 516: long n;
! 517: char *end;
! 518:
! 519: if (i && *s++ != '.')
! 520: return 0;
! 521: n = strtol(s, &end, 10);
! 522: if (n > 255 || n < 0 || end <= s || end > s+3)
! 523: return 0;
! 524: s = end;
! 525: }
! 526:
! 527: return !*s;
! 528: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>