関数 | |
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 |
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.c の 43 行で定義されています。
参照先 am_server・client_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] |
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.c の 95 行で定義されています。
参照先 addrinfo::ai_addr・addrinfo::ai_family・am_server・check_name()・client_addr()・client_sockaddr()・default_name・FLOG・freeaddrinfo()・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.c の 162 行で定義されています。
参照先 errno・FLOG・get_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.c の 211 行で定義されています。
参照先 client_addr()・default_name・FLOG・gai_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.c の 240 行で定義されています。
参照先 addrinfo::ai_addr・addrinfo::ai_addrlen・addrinfo::ai_family・FLOG・get_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.c の 303 行で定義されています。
参照先 addrinfo::ai_next・client_addr()・compare_addrinfo_sockaddr()・default_name・FLOG・freeaddrinfo()・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] |
int am_server |
参照元 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().