clientname.c

説明を見る。
00001 /* -*- c-file-style: "linux" -*-
00002 
00003    rsync -- fast file replication program
00004 
00005    Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
00006    Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 /**
00024  * @file clientname.c
00025  *
00026  * Functions for looking up the remote name or addr of a socket.
00027  *
00028  * This file is now converted to use the new-style getaddrinfo()
00029  * interface, which supports IPv6 but is also supported on recent
00030  * IPv4-only machines.  On systems that don't have that interface, we
00031  * emulate it using the KAME implementation.
00032  **/
00033 
00034 #include "rsync.h"
00035 
00036 static const char default_name[] = "UNKNOWN";
00037 extern int am_server;
00038 
00039 
00040 /**
00041  * Return the IP addr of the client as a string
00042  **/
00043 char *client_addr(int fd)
00044 {
00045         static char addr_buf[100];
00046         static int initialised;
00047         struct sockaddr_storage ss;
00048         socklen_t length = sizeof ss;
00049         char *ssh_info, *p;
00050 
00051         if (initialised)
00052                 return addr_buf;
00053 
00054         initialised = 1;
00055 
00056         if (am_server) {        /* daemon over --rsh mode */
00057                 strcpy(addr_buf, "0.0.0.0");
00058                 if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
00059                     || (ssh_info = getenv("SSH_CLIENT")) != NULL
00060                     || (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
00061                         strlcpy(addr_buf, ssh_info, sizeof addr_buf);
00062                         /* Truncate the value to just the IP address. */
00063                         if ((p = strchr(addr_buf, ' ')) != NULL)
00064                                 *p = '\0';
00065                 }
00066         } else {
00067                 client_sockaddr(fd, &ss, &length);
00068                 getnameinfo((struct sockaddr *)&ss, length,
00069                             addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
00070         }
00071 
00072         return addr_buf;
00073 }
00074 
00075 
00076 static int get_sockaddr_family(const struct sockaddr_storage *ss)
00077 {
00078         return ((struct sockaddr *) ss)->sa_family;
00079 }
00080 
00081 
00082 /**
00083  * Return the DNS name of the client.
00084  *
00085  * The name is statically cached so that repeated lookups are quick,
00086  * so there is a limit of one lookup per customer.
00087  *
00088  * If anything goes wrong, including the name->addr->name check, then
00089  * we just use "UNKNOWN", so you can use that value in hosts allow
00090  * lines.
00091  *
00092  * After translation from sockaddr to name we do a forward lookup to
00093  * make sure nobody is spoofing PTR records.
00094  **/
00095 char *client_name(int fd)
00096 {
00097         static char name_buf[100];
00098         static char port_buf[100];
00099         static int initialised;
00100         struct sockaddr_storage ss;
00101         socklen_t ss_len;
00102 
00103         if (initialised)
00104                 return name_buf;
00105 
00106         strcpy(name_buf, default_name);
00107         initialised = 1;
00108 
00109         memset(&ss, 0, sizeof ss);
00110 
00111         if (am_server) {        /* daemon over --rsh mode */
00112                 char *addr = client_addr(fd);
00113                 struct addrinfo hint, *answer;
00114                 int err;
00115 
00116                 memset(&hint, 0, sizeof hint);
00117 
00118 #ifdef AI_NUMERICHOST
00119                 hint.ai_flags = AI_NUMERICHOST;
00120 #endif
00121                 hint.ai_socktype = SOCK_STREAM;
00122 
00123                 if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
00124                         rprintf(FLOG, "malformed address %s: %s\n",
00125                                 addr, gai_strerror(err));
00126                         return name_buf;
00127                 }
00128 
00129                 switch (answer->ai_family) {
00130                 case AF_INET:
00131                         ss_len = sizeof (struct sockaddr_in);
00132                         memcpy(&ss, answer->ai_addr, ss_len);
00133                         break;
00134 #ifdef INET6
00135                 case AF_INET6:
00136                         ss_len = sizeof (struct sockaddr_in6);
00137                         memcpy(&ss, answer->ai_addr, ss_len);
00138                         break;
00139 #endif
00140                 }
00141                 freeaddrinfo(answer);
00142         } else {
00143                 ss_len = sizeof ss;
00144                 client_sockaddr(fd, &ss, &ss_len);
00145         }
00146 
00147         if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
00148                         port_buf, sizeof port_buf) == 0)
00149                 check_name(fd, &ss, name_buf);
00150 
00151         return name_buf;
00152 }
00153 
00154 
00155 
00156 /**
00157  * Get the sockaddr for the client.
00158  *
00159  * If it comes in as an ipv4 address mapped into IPv6 format then we
00160  * convert it back to a regular IPv4.
00161  **/
00162 void client_sockaddr(int fd,
00163                      struct sockaddr_storage *ss,
00164                      socklen_t *ss_len)
00165 {
00166         memset(ss, 0, sizeof *ss);
00167 
00168         if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
00169                 /* FIXME: Can we really not continue? */
00170                 rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
00171                 exit_cleanup(RERR_SOCKETIO);
00172         }
00173 
00174 #ifdef INET6
00175         if (get_sockaddr_family(ss) == AF_INET6 &&
00176             IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
00177                 /* OK, so ss is in the IPv6 family, but it is really
00178                  * an IPv4 address: something like
00179                  * "::ffff:10.130.1.2".  If we use it as-is, then the
00180                  * reverse lookup might fail or perhaps something else
00181                  * bad might happen.  So instead we convert it to an
00182                  * equivalent address in the IPv4 address family.  */
00183                 struct sockaddr_in6 sin6;
00184                 struct sockaddr_in *sin;
00185 
00186                 memcpy(&sin6, ss, sizeof sin6);
00187                 sin = (struct sockaddr_in *)ss;
00188                 memset(sin, 0, sizeof *sin);
00189                 sin->sin_family = AF_INET;
00190                 *ss_len = sizeof (struct sockaddr_in);
00191 #ifdef HAVE_SOCKADDR_IN_LEN
00192                 sin->sin_len = *ss_len;
00193 #endif
00194                 sin->sin_port = sin6.sin6_port;
00195 
00196                 /* There is a macro to extract the mapped part
00197                  * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
00198                  * to be present in the Linux headers. */
00199                 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
00200                     sizeof sin->sin_addr);
00201         }
00202 #endif
00203 }
00204 
00205 
00206 /**
00207  * Look up a name from @p ss into @p name_buf.
00208  *
00209  * @param fd file descriptor for client socket.
00210  **/
00211 int lookup_name(int fd, const struct sockaddr_storage *ss,
00212                 socklen_t ss_len,
00213                 char *name_buf, size_t name_buf_len,
00214                 char *port_buf, size_t port_buf_len)
00215 {
00216         int name_err;
00217 
00218         /* reverse lookup */
00219         name_err = getnameinfo((struct sockaddr *) ss, ss_len,
00220                                name_buf, name_buf_len,
00221                                port_buf, port_buf_len,
00222                                NI_NAMEREQD | NI_NUMERICSERV);
00223         if (name_err != 0) {
00224                 strcpy(name_buf, default_name);
00225                 rprintf(FLOG, "name lookup failed for %s: %s\n",
00226                         client_addr(fd), gai_strerror(name_err));
00227                 return name_err;
00228         }
00229 
00230         return 0;
00231 }
00232 
00233 
00234 
00235 /**
00236  * Compare an addrinfo from the resolver to a sockinfo.
00237  *
00238  * Like strcmp, returns 0 for identical.
00239  **/
00240 int compare_addrinfo_sockaddr(const struct addrinfo *ai,
00241                               const struct sockaddr_storage *ss)
00242 {
00243         int ss_family = get_sockaddr_family(ss);
00244         const char fn[] = "compare_addrinfo_sockaddr";
00245 
00246         if (ai->ai_family != ss_family) {
00247                 rprintf(FLOG, "%s: response family %d != %d\n",
00248                         fn, ai->ai_family, ss_family);
00249                 return 1;
00250         }
00251 
00252         /* The comparison method depends on the particular AF. */
00253         if (ss_family == AF_INET) {
00254                 const struct sockaddr_in *sin1, *sin2;
00255 
00256                 sin1 = (const struct sockaddr_in *) ss;
00257                 sin2 = (const struct sockaddr_in *) ai->ai_addr;
00258 
00259                 return memcmp(&sin1->sin_addr, &sin2->sin_addr,
00260                               sizeof sin1->sin_addr);
00261         }
00262 
00263 #ifdef INET6
00264         if (ss_family == AF_INET6) {
00265                 const struct sockaddr_in6 *sin1, *sin2;
00266 
00267                 sin1 = (const struct sockaddr_in6 *) ss;
00268                 sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
00269 
00270                 if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
00271                         rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
00272                                 fn, ai->ai_addrlen);
00273                         return 1;
00274                 }
00275 
00276                 if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
00277                            sizeof sin1->sin6_addr))
00278                         return 1;
00279 
00280 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
00281                 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
00282                         return 1;
00283 #endif
00284                 return 0;
00285         }
00286 #endif /* INET6 */
00287 
00288         /* don't know */
00289         return 1;
00290 }
00291 
00292 
00293 /**
00294  * Do a forward lookup on @p name_buf and make sure it corresponds to
00295  * @p ss -- otherwise we may be being spoofed.  If we suspect we are,
00296  * then we don't abort the connection but just emit a warning, and
00297  * change @p name_buf to be "UNKNOWN".
00298  *
00299  * We don't do anything with the service when checking the name,
00300  * because it doesn't seem that it could be spoofed in any way, and
00301  * getaddrinfo on random service names seems to cause problems on AIX.
00302  **/
00303 int check_name(int fd,
00304                const struct sockaddr_storage *ss,
00305                char *name_buf)
00306 {
00307         struct addrinfo hints, *res, *res0;
00308         int error;
00309         int ss_family = get_sockaddr_family(ss);
00310 
00311         memset(&hints, 0, sizeof hints);
00312         hints.ai_family = ss_family;
00313         hints.ai_flags = AI_CANONNAME;
00314         hints.ai_socktype = SOCK_STREAM;
00315         error = getaddrinfo(name_buf, NULL, &hints, &res0);
00316         if (error) {
00317                 rprintf(FLOG, "forward name lookup for %s failed: %s\n",
00318                         name_buf, gai_strerror(error));
00319                 strcpy(name_buf, default_name);
00320                 return error;
00321         }
00322 
00323         /* Given all these results, we expect that one of them will be
00324          * the same as ss.  The comparison is a bit complicated. */
00325         for (res = res0; res; res = res->ai_next) {
00326                 if (!compare_addrinfo_sockaddr(res, ss))
00327                         break;  /* OK, identical */
00328         }
00329 
00330         if (!res0) {
00331                 /* We hit the end of the list without finding an
00332                  * address that was the same as ss. */
00333                 rprintf(FLOG, "no known address for \"%s\": "
00334                         "spoofed address?\n", name_buf);
00335                 strcpy(name_buf, default_name);
00336         } else if (res == NULL) {
00337                 /* We hit the end of the list without finding an
00338                  * address that was the same as ss. */
00339                 rprintf(FLOG, "%s is not a known address for \"%s\": "
00340                         "spoofed address?\n", client_addr(fd), name_buf);
00341                 strcpy(name_buf, default_name);
00342         }
00343 
00344         freeaddrinfo(res0);
00345         return 0;
00346 }

rsyncに対してSat Dec 5 19:45:40 2009に生成されました。  doxygen 1.4.7