File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / clientname.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    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>
    6:  * Copyright (C) 2002-2020 Wayne Davison
    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"
   30: #include "itypes.h"
   31: 
   32: extern int am_daemon;
   33: 
   34: static const char default_name[] = "UNKNOWN";
   35: static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n";
   36: 
   37: static char ipaddr_buf[100];
   38: 
   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. */
   55: char *client_addr(int fd)
   56: {
   57: 	struct sockaddr_storage ss;
   58: 	socklen_t length = sizeof ss;
   59: 
   60: 	if (*ipaddr_buf)
   61: 		return ipaddr_buf;
   62: 
   63: 	if (am_daemon < 0) {	/* daemon over --rsh mode */
   64: 		char *env_str;
   65: 		strlcpy(ipaddr_buf, "0.0.0.0", sizeof ipaddr_buf);
   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;
   71: 			strlcpy(ipaddr_buf, env_str, sizeof ipaddr_buf);
   72: 			/* Truncate the value to just the IP address. */
   73: 			if ((p = strchr(ipaddr_buf, ' ')) != NULL)
   74: 				*p = '\0';
   75: 		}
   76: 		if (valid_ipaddr(ipaddr_buf))
   77: 			return ipaddr_buf;
   78: 	}
   79: 
   80: 	client_sockaddr(fd, &ss, &length);
   81: 	getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST);
   82: 
   83: 	return ipaddr_buf;
   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:  **/
  100: char *client_name(const char *ipaddr)
  101: {
  102: 	static char name_buf[100];
  103: 	char port_buf[100];
  104: 	struct sockaddr_storage ss;
  105: 	socklen_t ss_len;
  106: 	struct addrinfo hint, *answer;
  107: 	int err;
  108: 
  109: 	if (*name_buf)
  110: 		return name_buf;
  111: 
  112: 	strlcpy(name_buf, default_name, sizeof name_buf);
  113: 
  114: 	if (strcmp(ipaddr, "0.0.0.0") == 0)
  115: 		return name_buf;
  116: 
  117: 	memset(&ss, 0, sizeof ss);
  118: 	memset(&hint, 0, sizeof hint);
  119: 
  120: #ifdef AI_NUMERICHOST
  121: 	hint.ai_flags = AI_NUMERICHOST;
  122: #endif
  123: 	hint.ai_socktype = SOCK_STREAM;
  124: 
  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: 	}
  129: 
  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;
  135: #ifdef INET6
  136: 	case AF_INET6:
  137: 		ss_len = sizeof (struct sockaddr_in6);
  138: 		memcpy(&ss, answer->ai_addr, ss_len);
  139: 		break;
  140: #endif
  141: 	default:
  142: 		NOISY_DEATH("Unknown ai_family value");
  143: 	}
  144: 	freeaddrinfo(answer);
  145: 
  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);
  154: 
  155: 	return name_buf;
  156: }
  157: 
  158: 
  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: 
  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:  **/
  317: static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
  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
  328: 	if (GET_SOCKADDR_FAMILY(ss) == AF_INET6
  329: 	 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
  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. */
  352: 		memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr);
  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:  **/
  363: static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss)
  364: {
  365: 	int ss_family = GET_SOCKADDR_FAMILY(ss);
  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: 
  381: 		return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof sin1->sin_addr);
  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: 
  391: 		if (ai->ai_addrlen < (int)sizeof (struct sockaddr_in6)) {
  392: 			rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
  393: 				fn, (int)ai->ai_addrlen);
  394: 			return 1;
  395: 		}
  396: 
  397: 		if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof sin1->sin6_addr))
  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:  **/
  423: static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size)
  424: {
  425: 	struct addrinfo hints, *res, *res0;
  426: 	int error;
  427: 	int ss_family = GET_SOCKADDR_FAMILY(ss);
  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\": "
  458: 			"spoofed address?\n", ipaddr, name_buf);
  459: 		strlcpy(name_buf, default_name, name_buf_size);
  460: 	}
  461: 
  462: 	freeaddrinfo(res0);
  463: 	return 0;
  464: }
  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>