Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

clientname.c

Go to the documentation of this file.
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 
00038 
00039 /**
00040  * Return the IP addr of the client as a string 
00041  **/
00042 char *client_addr(int fd)
00043 {
00044         struct sockaddr_storage ss;
00045         socklen_t length = sizeof ss;
00046         static char addr_buf[100];
00047         static int initialised;
00048 
00049         if (initialised) return addr_buf;
00050 
00051         initialised = 1;
00052 
00053         client_sockaddr(fd, &ss, &length);
00054 
00055         getnameinfo((struct sockaddr *)&ss, length,
00056                     addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
00057         
00058         return addr_buf;
00059 }
00060 
00061 
00062 static int get_sockaddr_family(const struct sockaddr_storage *ss)
00063 {
00064         return ((struct sockaddr *) ss)->sa_family;
00065 }
00066 
00067 
00068 /**
00069  * Return the DNS name of the client.
00070  *
00071  * The name is statically cached so that repeated lookups are quick,
00072  * so there is a limit of one lookup per customer.
00073  *
00074  * If anything goes wrong, including the name->addr->name check, then
00075  * we just use "UNKNOWN", so you can use that value in hosts allow
00076  * lines.
00077  *
00078  * After translation from sockaddr to name we do a forward lookup to
00079  * make sure nobody is spoofing PTR records.
00080  **/
00081 char *client_name(int fd)
00082 {
00083         struct sockaddr_storage ss;
00084         socklen_t ss_len = sizeof ss;
00085         static char name_buf[100];
00086         static char port_buf[100];
00087         static int initialised;
00088 
00089         if (initialised) return name_buf;
00090 
00091         strcpy(name_buf, default_name);
00092         initialised = 1;
00093 
00094         client_sockaddr(fd, &ss, &ss_len);
00095 
00096         if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
00097                          port_buf, sizeof port_buf))
00098                 check_name(fd, &ss, name_buf);
00099 
00100         return name_buf;
00101 }
00102 
00103 
00104 
00105 /**
00106  * Get the sockaddr for the client.
00107  *
00108  * If it comes in as an ipv4 address mapped into IPv6 format then we
00109  * convert it back to a regular IPv4.
00110  **/
00111 void client_sockaddr(int fd,
00112                      struct sockaddr_storage *ss,
00113                      socklen_t *ss_len)
00114 {
00115         if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
00116                 /* FIXME: Can we really not continue? */
00117                 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
00118                         fd, strerror(errno));
00119                 exit_cleanup(RERR_SOCKETIO);
00120         }
00121 
00122 #ifdef INET6
00123         if (get_sockaddr_family(ss) == AF_INET6 && 
00124             IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
00125                 /* OK, so ss is in the IPv6 family, but it is really
00126                  * an IPv4 address: something like
00127                  * "::ffff:10.130.1.2".  If we use it as-is, then the
00128                  * reverse lookup might fail or perhaps something else
00129                  * bad might happen.  So instead we convert it to an
00130                  * equivalent address in the IPv4 address family.  */
00131                 struct sockaddr_in6 sin6;
00132                 struct sockaddr_in *sin;
00133 
00134                 memcpy(&sin6, ss, sizeof(sin6));
00135                 sin = (struct sockaddr_in *)ss;
00136                 memset(sin, 0, sizeof(*sin));
00137                 sin->sin_family = AF_INET;
00138                 *ss_len = sizeof(struct sockaddr_in);
00139 #ifdef HAVE_SOCKADDR_LEN
00140                 sin->sin_len = *ss_len;
00141 #endif
00142                 sin->sin_port = sin6.sin6_port;
00143 
00144                 /* There is a macro to extract the mapped part
00145                  * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
00146                  * to be present in the Linux headers. */
00147                 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
00148                         sizeof(sin->sin_addr));
00149         }
00150 #endif
00151 }
00152 
00153 
00154 /**
00155  * Look up a name from @p ss into @p name_buf.
00156  *
00157  * @param fd file descriptor for client socket.
00158  **/
00159 int lookup_name(int fd, const struct sockaddr_storage *ss,
00160                 socklen_t ss_len,
00161                 char *name_buf, size_t name_buf_len,
00162                 char *port_buf, size_t port_buf_len)
00163 {
00164         int name_err;
00165         
00166         /* reverse lookup */
00167         name_err = getnameinfo((struct sockaddr *) ss, ss_len,
00168                                name_buf, name_buf_len,
00169                                port_buf, port_buf_len,
00170                                NI_NAMEREQD | NI_NUMERICSERV);
00171         if (name_err != 0) {
00172                 strcpy(name_buf, default_name);
00173                 rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
00174                         client_addr(fd),
00175                         gai_strerror(name_err));
00176                 return name_err;
00177         }
00178 
00179         return 0;
00180 }
00181 
00182 
00183 
00184 /**
00185  * Compare an addrinfo from the resolver to a sockinfo.
00186  *
00187  * Like strcmp, returns 0 for identical.
00188  **/
00189 int compare_addrinfo_sockaddr(const struct addrinfo *ai,
00190                               const struct sockaddr_storage *ss)
00191 {
00192         int ss_family = get_sockaddr_family(ss);
00193         const char fn[] = "compare_addrinfo_sockaddr";
00194                       
00195         if (ai->ai_family != ss_family) {
00196                 rprintf(FERROR,
00197                         "%s: response family %d != %d\n",
00198                         fn, ai->ai_family, ss_family);
00199                 return 1;
00200         }
00201 
00202         /* The comparison method depends on the particular AF. */
00203         if (ss_family == AF_INET) {
00204                 const struct sockaddr_in *sin1, *sin2;
00205 
00206                 sin1 = (const struct sockaddr_in *) ss;
00207                 sin2 = (const struct sockaddr_in *) ai->ai_addr;
00208                 
00209                 return memcmp(&sin1->sin_addr, &sin2->sin_addr,
00210                               sizeof sin1->sin_addr);
00211         }
00212 #ifdef INET6
00213         else if (ss_family == AF_INET6) {
00214                 const struct sockaddr_in6 *sin1, *sin2;
00215 
00216                 sin1 = (const struct sockaddr_in6 *) ss;
00217                 sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
00218                 
00219                 return memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
00220                               sizeof sin1->sin6_addr);
00221         }
00222 #endif /* INET6 */
00223         else {
00224                 /* don't know */
00225                 return 1;
00226         }
00227 }
00228 
00229 
00230 /**
00231  * Do a forward lookup on @p name_buf and make sure it corresponds to
00232  * @p ss -- otherwise we may be being spoofed.  If we suspect we are,
00233  * then we don't abort the connection but just emit a warning, and
00234  * change @p name_buf to be "UNKNOWN".
00235  *
00236  * We don't do anything with the service when checking the name,
00237  * because it doesn't seem that it could be spoofed in any way, and
00238  * getaddrinfo on random service names seems to cause problems on AIX.
00239  **/
00240 int check_name(int fd,
00241                const struct sockaddr_storage *ss,
00242                char *name_buf)
00243 {
00244         struct addrinfo hints, *res, *res0;
00245         int error;
00246         int ss_family = get_sockaddr_family(ss);
00247 
00248         memset(&hints, 0, sizeof(hints));
00249         hints.ai_family = ss_family;
00250         hints.ai_flags = AI_CANONNAME;
00251         hints.ai_socktype = SOCK_STREAM;
00252         error = getaddrinfo(name_buf, NULL, &hints, &res0);
00253         if (error) {
00254                 rprintf(FERROR,
00255                         RSYNC_NAME ": forward name lookup for %s failed: %s\n",
00256                         name_buf, gai_strerror(error));
00257                 strcpy(name_buf, default_name);
00258                 return error;
00259         }
00260 
00261 
00262         /* Given all these results, we expect that one of them will be
00263          * the same as ss.  The comparison is a bit complicated. */
00264         for (res = res0; res; res = res->ai_next) {
00265                 if (!compare_addrinfo_sockaddr(res, ss))
00266                         break;  /* OK, identical */
00267         }
00268 
00269         if (!res0) {
00270                 /* We hit the end of the list without finding an
00271                  * address that was the same as ss. */
00272                 rprintf(FERROR, RSYNC_NAME
00273                         ": no known address for \"%s\": "
00274                         "spoofed address?\n",
00275                         name_buf);
00276                 strcpy(name_buf, default_name);
00277         } else if (res == NULL) {
00278                 /* We hit the end of the list without finding an
00279                  * address that was the same as ss. */
00280                 rprintf(FERROR, RSYNC_NAME
00281                         ": %s is not a known address for \"%s\": "
00282                         "spoofed address?\n",
00283                         client_addr(fd),
00284                         name_buf);
00285                 strcpy(name_buf, default_name);
00286         }
00287 
00288         freeaddrinfo(res0);
00289         return 0;
00290 }
00291 

Generated on Tue Apr 16 12:37:36 2002 for rsync by doxygen1.2.15