* 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. **/
| 317 | * convert it back to a regular IPv4. |
| 318 | **/ |
| 319 | static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len) |
| 320 | { |
| 321 | memset(ss, 0, sizeof *ss); |
| 322 | |
| 323 | if (getpeername(fd, (struct sockaddr *) ss, ss_len)) { |
| 324 | /* FIXME: Can we really not continue? */ |
| 325 | rsyserr(FLOG, errno, "getpeername on fd%d failed", fd); |
| 326 | exit_cleanup(RERR_SOCKETIO); |
| 327 | } |
| 328 | |
| 329 | #ifdef INET6 |
| 330 | if (GET_SOCKADDR_FAMILY(ss) == AF_INET6 |
| 331 | && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) { |
| 332 | /* OK, so ss is in the IPv6 family, but it is really |
| 333 | * an IPv4 address: something like |
| 334 | * "::ffff:10.130.1.2". If we use it as-is, then the |
| 335 | * reverse lookup might fail or perhaps something else |
| 336 | * bad might happen. So instead we convert it to an |
| 337 | * equivalent address in the IPv4 address family. */ |
| 338 | struct sockaddr_in6 sin6; |
| 339 | struct sockaddr_in *sin; |
| 340 | |
| 341 | memcpy(&sin6, ss, sizeof sin6); |
| 342 | sin = (struct sockaddr_in *)ss; |
| 343 | memset(sin, 0, sizeof *sin); |
| 344 | sin->sin_family = AF_INET; |
| 345 | *ss_len = sizeof (struct sockaddr_in); |
| 346 | #ifdef HAVE_SOCKADDR_IN_LEN |
| 347 | sin->sin_len = *ss_len; |
| 348 | #endif |
| 349 | sin->sin_port = sin6.sin6_port; |
| 350 | |
| 351 | /* There is a macro to extract the mapped part |
| 352 | * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem |
| 353 | * to be present in the Linux headers. */ |
| 354 | memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr); |
| 355 | } |
| 356 | #endif |
| 357 | } |
| 358 | |
| 359 | |
| 360 | /** |
no test coverage detected