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

clientname.c File Reference

Functions for looking up the remote name or addr of a socket. More...

Go to the source code of this file.

Functions

char * client_addr (int fd)
 Return the IP addr of the client as a string. More...

int get_sockaddr_family (const struct sockaddr_storage *ss)
char * client_name (int fd)
 Return the DNS name of the client. More...

void client_sockaddr (int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
 Get the sockaddr for the client. More...

int lookup_name (int fd, const struct sockaddr_storage *ss, socklen_t ss_len, char *name_buf, size_t name_buf_len, char *port_buf, size_t port_buf_len)
 Look up a name from ss into name_buf. More...

int compare_addrinfo_sockaddr (const struct addrinfo *ai, const struct sockaddr_storage *ss)
 Compare an addrinfo from the resolver to a sockinfo. More...

int check_name (int fd, const struct sockaddr_storage *ss, char *name_buf)
 Do a forward lookup on name_buf and make sure it corresponds to ss -- otherwise we may be being spoofed. More...


Variables

const char default_name [] = "UNKNOWN"


Detailed Description

Functions for looking up the remote name or addr of a socket.

This file is now converted to use the new-style getaddrinfo() interface, which supports IPv6 but is also supported on recent IPv4-only machines. On systems that don't have that interface, we emulate it using the KAME implementation.

Definition in file clientname.c.


Function Documentation

char* client_addr int    fd
 

Return the IP addr of the client as a string.

Definition at line 42 of file clientname.c.

References client_sockaddr(), and getnameinfo().

Referenced by check_name(), log_formatted(), lookup_name(), and rsync_module().

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 }

int get_sockaddr_family const struct sockaddr_storage   ss [static]
 

Definition at line 62 of file clientname.c.

Referenced by check_name(), client_sockaddr(), and compare_addrinfo_sockaddr().

00063 {
00064         return ((struct sockaddr *) ss)->sa_family;
00065 }

char* client_name int    fd
 

Return the DNS name of the client.

The name is statically cached so that repeated lookups are quick, so there is a limit of one lookup per customer.

If anything goes wrong, including the name->addr->name check, then we just use "UNKNOWN", so you can use that value in hosts allow lines.

After translation from sockaddr to name we do a forward lookup to make sure nobody is spoofing PTR records.

Definition at line 81 of file clientname.c.

References check_name(), client_sockaddr(), default_name, and lookup_name().

Referenced by log_formatted(), and rsync_module().

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 }

void client_sockaddr int    fd,
struct sockaddr_storage   ss,
socklen_t *    ss_len
 

Get the sockaddr for the client.

If it comes in as an ipv4 address mapped into IPv6 format then we convert it back to a regular IPv4.

Definition at line 111 of file clientname.c.

References FERROR, get_sockaddr_family(), and rprintf().

Referenced by client_addr(), and client_name().

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 }

int lookup_name int    fd,
const struct sockaddr_storage   ss,
socklen_t    ss_len,
char *    name_buf,
size_t    name_buf_len,
char *    port_buf,
size_t    port_buf_len
 

Look up a name from ss into name_buf.

Parameters:
fd  file descriptor for client socket.

Definition at line 159 of file clientname.c.

References client_addr(), default_name, FERROR, gai_strerror(), getnameinfo(), and rprintf().

Referenced by client_name().

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 }

int compare_addrinfo_sockaddr const struct addrinfo   ai,
const struct sockaddr_storage   ss
 

Compare an addrinfo from the resolver to a sockinfo.

Like strcmp, returns 0 for identical.

Definition at line 189 of file clientname.c.

References addrinfo::ai_family, FERROR, get_sockaddr_family(), and rprintf().

Referenced by check_name().

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 }

int check_name int    fd,
const struct sockaddr_storage   ss,
char *    name_buf
 

Do a forward lookup on name_buf and make sure it corresponds to ss -- otherwise we may be being spoofed.

If we suspect we are, then we don't abort the connection but just emit a warning, and change name_buf to be "UNKNOWN".

We don't do anything with the service when checking the name, because it doesn't seem that it could be spoofed in any way, and getaddrinfo on random service names seems to cause problems on AIX.

Definition at line 240 of file clientname.c.

References addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, addrinfo::ai_socktype, client_addr(), compare_addrinfo_sockaddr(), default_name, FERROR, gai_strerror(), get_sockaddr_family(), and rprintf().

Referenced by client_name().

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 }


Variable Documentation

const char default_name[] = "UNKNOWN" [static]
 

Definition at line 36 of file clientname.c.

Referenced by check_name(), client_name(), and lookup_name().


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