clientname.c

Functions for looking up the remote name or addr of a socket. [詳細]

ソースコードを見る。


関数

char * client_addr (int fd)
 Return the IP addr of the client as a string
static int get_sockaddr_family (const struct sockaddr_storage *ss)
char * client_name (int fd)
 Return the DNS name of the client.
void client_sockaddr (int fd, struct sockaddr_storage *ss, socklen_t *ss_len)
 Get the sockaddr for the client.
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.
int compare_addrinfo_sockaddr (const struct addrinfo *ai, const struct sockaddr_storage *ss)
 Compare an addrinfo from the resolver to a sockinfo.
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.

変数

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

説明

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.

clientname.c で定義されています。


関数

char* client_addr ( int  fd  ) 

Return the IP addr of the client as a string

clientname.c43 行で定義されています。

参照先 am_serverclient_sockaddr()getnameinfo()strlcpy().

参照元 check_name()client_name()log_formatted()lookup_name()start_daemon().

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 }

static int get_sockaddr_family ( const struct sockaddr_storage ss  )  [static]

clientname.c76 行で定義されています。

参照元 check_name()client_sockaddr()compare_addrinfo_sockaddr().

00077 {
00078         return ((struct sockaddr *) ss)->sa_family;
00079 }

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.

clientname.c95 行で定義されています。

参照先 addrinfo::ai_addraddrinfo::ai_familyam_servercheck_name()client_addr()client_sockaddr()default_nameFLOGfreeaddrinfo()gai_strerror()getaddrinfo()lookup_name()rprintf().

参照元 log_formatted()start_daemon().

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 }

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.

clientname.c162 行で定義されています。

参照先 errnoFLOGget_sockaddr_family()rsyserr().

参照元 client_addr()client_name().

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 }

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.

引数:
fd file descriptor for client socket.

clientname.c211 行で定義されています。

参照先 client_addr()default_nameFLOGgai_strerror()getnameinfo()rprintf().

参照元 client_name().

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 }

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.

clientname.c240 行で定義されています。

参照先 addrinfo::ai_addraddrinfo::ai_addrlenaddrinfo::ai_familyFLOGget_sockaddr_family()rprintf().

参照元 check_name().

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 }

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.

clientname.c303 行で定義されています。

参照先 addrinfo::ai_nextclient_addr()compare_addrinfo_sockaddr()default_nameFLOGfreeaddrinfo()gai_strerror()get_sockaddr_family()getaddrinfo()rprintf().

参照元 client_name().

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 }


変数

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

clientname.c36 行で定義されています。

参照元 check_name()client_name()lookup_name().

int am_server

options.c75 行で定義されています。

参照元 check_timeout()clean_flist()client_addr()client_name()client_run()do_delete_pass()do_recv()end_progress()generate_files()handle_stats()local_child()log_delete()log_item()lp_load()main()maybe_log_item()parse_arguments()parse_filter_file()read_msg_fd()recv_files()rflush()rsync_module()rwrite()send_files()setup_iconv()setup_protocol()show_filelist_p()show_malloc_stats()show_progress()sigusr2_handler()start_daemon()who_am_i().


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